1fcbc3db1SBrandon Kim #include "buffer.hpp"
2fcbc3db1SBrandon Kim #include "data_interface_mock.hpp"
3fcbc3db1SBrandon Kim
417ee1a93SBrandon Kim #include <boost/endian/arithmetic.hpp>
517ee1a93SBrandon Kim #include <boost/endian/conversion.hpp>
617ee1a93SBrandon Kim
717ee1a93SBrandon Kim #include <algorithm>
8fcbc3db1SBrandon Kim #include <array>
9fcbc3db1SBrandon Kim #include <cstdint>
10fcbc3db1SBrandon Kim #include <memory>
11fcbc3db1SBrandon Kim
12fcbc3db1SBrandon Kim #include <gmock/gmock.h>
13fcbc3db1SBrandon Kim #include <gtest/gtest.h>
14fcbc3db1SBrandon Kim
15fcbc3db1SBrandon Kim namespace bios_bmc_smm_error_logger
16fcbc3db1SBrandon Kim {
17fcbc3db1SBrandon Kim namespace
18fcbc3db1SBrandon Kim {
19fcbc3db1SBrandon Kim
20fcbc3db1SBrandon Kim using ::testing::_;
21fcbc3db1SBrandon Kim using ::testing::ElementsAreArray;
22fcbc3db1SBrandon Kim using ::testing::InSequence;
23fcbc3db1SBrandon Kim using ::testing::Return;
24fcbc3db1SBrandon Kim
25fcbc3db1SBrandon Kim class BufferTest : public ::testing::Test
26fcbc3db1SBrandon Kim {
27fcbc3db1SBrandon Kim protected:
BufferTest()28fcbc3db1SBrandon Kim BufferTest() :
29fcbc3db1SBrandon Kim dataInterfaceMock(std::make_unique<DataInterfaceMock>()),
30fcbc3db1SBrandon Kim dataInterfaceMockPtr(dataInterfaceMock.get())
31fcbc3db1SBrandon Kim {
32fcbc3db1SBrandon Kim bufferImpl = std::make_unique<BufferImpl>(std::move(dataInterfaceMock));
33fcbc3db1SBrandon Kim testInitializationHeader.bmcInterfaceVersion = testBmcInterfaceVersion;
34fcbc3db1SBrandon Kim testInitializationHeader.queueSize = testQueueSize;
35fcbc3db1SBrandon Kim testInitializationHeader.ueRegionSize = testUeRegionSize;
3617ee1a93SBrandon Kim std::transform(testMagicNumber.begin(), testMagicNumber.end(),
3717ee1a93SBrandon Kim testInitializationHeader.magicNumber.begin(),
3817ee1a93SBrandon Kim [](uint32_t number) -> little_uint32_t {
3917ee1a93SBrandon Kim return boost::endian::native_to_little(number);
4017ee1a93SBrandon Kim });
41fcbc3db1SBrandon Kim }
42fcbc3db1SBrandon Kim ~BufferTest() override = default;
43fcbc3db1SBrandon Kim
44fcbc3db1SBrandon Kim // CircularBufferHeader size is 0x30, ensure the test region is bigger
45fcbc3db1SBrandon Kim static constexpr size_t testRegionSize = 0x200;
46fcbc3db1SBrandon Kim static constexpr uint32_t testBmcInterfaceVersion = 123;
473def3c8eSBrandon Kim static constexpr uint32_t testQueueSize = 0x200;
48fcbc3db1SBrandon Kim static constexpr uint16_t testUeRegionSize = 0x50;
49fcbc3db1SBrandon Kim static constexpr std::array<uint32_t, 4> testMagicNumber = {
50fcbc3db1SBrandon Kim 0x12345678, 0x22345678, 0x32345678, 0x42345678};
5117ee1a93SBrandon Kim static constexpr size_t bufferHeaderSize =
5217ee1a93SBrandon Kim sizeof(struct CircularBufferHeader);
5317ee1a93SBrandon Kim
54*c20d1216SPatrick Williams struct CircularBufferHeader testInitializationHeader{};
55fcbc3db1SBrandon Kim
56fcbc3db1SBrandon Kim std::unique_ptr<DataInterfaceMock> dataInterfaceMock;
57fcbc3db1SBrandon Kim DataInterfaceMock* dataInterfaceMockPtr;
58fcbc3db1SBrandon Kim std::unique_ptr<BufferImpl> bufferImpl;
59fcbc3db1SBrandon Kim };
60fcbc3db1SBrandon Kim
TEST_F(BufferTest,BufferInitializeEraseFail)61fcbc3db1SBrandon Kim TEST_F(BufferTest, BufferInitializeEraseFail)
62fcbc3db1SBrandon Kim {
63fcbc3db1SBrandon Kim InSequence s;
6426660e9bSBrandon Kim EXPECT_CALL(*dataInterfaceMockPtr, getMemoryRegionSize())
6526660e9bSBrandon Kim .WillOnce(Return(testRegionSize));
6626660e9bSBrandon Kim EXPECT_THROW(
6726660e9bSBrandon Kim try {
6826660e9bSBrandon Kim // Test too big of a proposed buffer compared to the memori size
693def3c8eSBrandon Kim uint16_t bigQueueSize = 0x201;
7026660e9bSBrandon Kim uint16_t bigUeRegionSize = 0x50;
7126660e9bSBrandon Kim bufferImpl->initialize(testBmcInterfaceVersion, bigQueueSize,
7226660e9bSBrandon Kim bigUeRegionSize, testMagicNumber);
7326660e9bSBrandon Kim } catch (const std::runtime_error& e) {
7426660e9bSBrandon Kim EXPECT_STREQ(
7526660e9bSBrandon Kim e.what(),
763def3c8eSBrandon Kim "[initialize] Proposed queue size '513' is bigger than the BMC's allocated MMIO region of '512'");
7726660e9bSBrandon Kim throw;
7826660e9bSBrandon Kim },
7926660e9bSBrandon Kim std::runtime_error);
8026660e9bSBrandon Kim EXPECT_NE(bufferImpl->getCachedBufferHeader(), testInitializationHeader);
81fcbc3db1SBrandon Kim
82fcbc3db1SBrandon Kim EXPECT_CALL(*dataInterfaceMockPtr, getMemoryRegionSize())
83fcbc3db1SBrandon Kim .WillOnce(Return(testRegionSize));
843def3c8eSBrandon Kim const std::vector<uint8_t> emptyArray(testQueueSize, 0);
85fcbc3db1SBrandon Kim // Return a smaller write than the intended testRegionSize to test the error
86fcbc3db1SBrandon Kim EXPECT_CALL(*dataInterfaceMockPtr, write(0, ElementsAreArray(emptyArray)))
873def3c8eSBrandon Kim .WillOnce(Return(testQueueSize - 1));
88fcbc3db1SBrandon Kim EXPECT_THROW(
89fcbc3db1SBrandon Kim try {
90fcbc3db1SBrandon Kim bufferImpl->initialize(testBmcInterfaceVersion, testQueueSize,
91fcbc3db1SBrandon Kim testUeRegionSize, testMagicNumber);
92fcbc3db1SBrandon Kim } catch (const std::runtime_error& e) {
933def3c8eSBrandon Kim EXPECT_STREQ(e.what(), "[initialize] Only erased '511'");
94fcbc3db1SBrandon Kim throw;
95fcbc3db1SBrandon Kim },
96fcbc3db1SBrandon Kim std::runtime_error);
9760cab57fSBrandon Kim EXPECT_NE(bufferImpl->getCachedBufferHeader(), testInitializationHeader);
98fcbc3db1SBrandon Kim
99fcbc3db1SBrandon Kim EXPECT_CALL(*dataInterfaceMockPtr, getMemoryRegionSize())
100fcbc3db1SBrandon Kim .WillOnce(Return(testRegionSize));
101fcbc3db1SBrandon Kim EXPECT_CALL(*dataInterfaceMockPtr, write(0, ElementsAreArray(emptyArray)))
1023def3c8eSBrandon Kim .WillOnce(Return(testQueueSize));
103fcbc3db1SBrandon Kim // Return a smaller write than the intended initializationHeader to test the
104fcbc3db1SBrandon Kim // error
105fcbc3db1SBrandon Kim EXPECT_CALL(*dataInterfaceMockPtr, write(0, _)).WillOnce(Return(0));
106fcbc3db1SBrandon Kim EXPECT_THROW(
107fcbc3db1SBrandon Kim try {
108fcbc3db1SBrandon Kim bufferImpl->initialize(testBmcInterfaceVersion, testQueueSize,
109fcbc3db1SBrandon Kim testUeRegionSize, testMagicNumber);
110fcbc3db1SBrandon Kim } catch (const std::runtime_error& e) {
11126660e9bSBrandon Kim EXPECT_STREQ(e.what(),
11226660e9bSBrandon Kim "[initialize] Only wrote '0' bytes of the header");
113fcbc3db1SBrandon Kim throw;
114fcbc3db1SBrandon Kim },
115fcbc3db1SBrandon Kim std::runtime_error);
11660cab57fSBrandon Kim EXPECT_NE(bufferImpl->getCachedBufferHeader(), testInitializationHeader);
117fcbc3db1SBrandon Kim }
118fcbc3db1SBrandon Kim
TEST_F(BufferTest,BufferInitializePass)119fcbc3db1SBrandon Kim TEST_F(BufferTest, BufferInitializePass)
120fcbc3db1SBrandon Kim {
121fcbc3db1SBrandon Kim InSequence s;
122fcbc3db1SBrandon Kim EXPECT_CALL(*dataInterfaceMockPtr, getMemoryRegionSize())
123fcbc3db1SBrandon Kim .WillOnce(Return(testRegionSize));
1243def3c8eSBrandon Kim const std::vector<uint8_t> emptyArray(testQueueSize, 0);
125fcbc3db1SBrandon Kim EXPECT_CALL(*dataInterfaceMockPtr, write(0, ElementsAreArray(emptyArray)))
1263def3c8eSBrandon Kim .WillOnce(Return(testQueueSize));
127fcbc3db1SBrandon Kim
128fcbc3db1SBrandon Kim uint8_t* testInitializationHeaderPtr =
129fcbc3db1SBrandon Kim reinterpret_cast<uint8_t*>(&testInitializationHeader);
130fcbc3db1SBrandon Kim EXPECT_CALL(*dataInterfaceMockPtr,
131fcbc3db1SBrandon Kim write(0, ElementsAreArray(testInitializationHeaderPtr,
13217ee1a93SBrandon Kim bufferHeaderSize)))
13317ee1a93SBrandon Kim .WillOnce(Return(bufferHeaderSize));
1341a64356fSPatrick Williams EXPECT_NO_THROW(
1351a64356fSPatrick Williams bufferImpl->initialize(testBmcInterfaceVersion, testQueueSize,
1361a64356fSPatrick Williams testUeRegionSize, testMagicNumber));
13760cab57fSBrandon Kim EXPECT_EQ(bufferImpl->getCachedBufferHeader(), testInitializationHeader);
138fcbc3db1SBrandon Kim }
139fcbc3db1SBrandon Kim
TEST_F(BufferTest,BufferHeaderReadFail)14017ee1a93SBrandon Kim TEST_F(BufferTest, BufferHeaderReadFail)
14117ee1a93SBrandon Kim {
14217ee1a93SBrandon Kim std::vector<std::uint8_t> testBytesRead{};
14317ee1a93SBrandon Kim EXPECT_CALL(*dataInterfaceMockPtr, read(0, bufferHeaderSize))
14417ee1a93SBrandon Kim .WillOnce(Return(testBytesRead));
14517ee1a93SBrandon Kim EXPECT_THROW(
14617ee1a93SBrandon Kim try {
14717ee1a93SBrandon Kim bufferImpl->readBufferHeader();
14817ee1a93SBrandon Kim } catch (const std::runtime_error& e) {
14917ee1a93SBrandon Kim EXPECT_STREQ(e.what(),
15017ee1a93SBrandon Kim "Buffer header read only read '0', expected '48'");
15117ee1a93SBrandon Kim throw;
15217ee1a93SBrandon Kim },
15317ee1a93SBrandon Kim std::runtime_error);
15417ee1a93SBrandon Kim }
15517ee1a93SBrandon Kim
TEST_F(BufferTest,BufferHeaderReadPass)15617ee1a93SBrandon Kim TEST_F(BufferTest, BufferHeaderReadPass)
15717ee1a93SBrandon Kim {
15817ee1a93SBrandon Kim uint8_t* testInitializationHeaderPtr =
15917ee1a93SBrandon Kim reinterpret_cast<uint8_t*>(&testInitializationHeader);
16017ee1a93SBrandon Kim std::vector<uint8_t> testInitializationHeaderVector(
16117ee1a93SBrandon Kim testInitializationHeaderPtr,
16217ee1a93SBrandon Kim testInitializationHeaderPtr + bufferHeaderSize);
16317ee1a93SBrandon Kim
16417ee1a93SBrandon Kim EXPECT_CALL(*dataInterfaceMockPtr, read(0, bufferHeaderSize))
16517ee1a93SBrandon Kim .WillOnce(Return(testInitializationHeaderVector));
16617ee1a93SBrandon Kim EXPECT_NO_THROW(bufferImpl->readBufferHeader());
16717ee1a93SBrandon Kim EXPECT_EQ(bufferImpl->getCachedBufferHeader(), testInitializationHeader);
16817ee1a93SBrandon Kim }
16917ee1a93SBrandon Kim
TEST_F(BufferTest,BufferUpdateReadPtrFail)170cf0b9752SBrandon Kim TEST_F(BufferTest, BufferUpdateReadPtrFail)
171cf0b9752SBrandon Kim {
172cf0b9752SBrandon Kim // Return write size that is not 2 which is sizeof(little_uint16_t)
173cf0b9752SBrandon Kim constexpr size_t wrongWriteSize = 1;
174cf0b9752SBrandon Kim EXPECT_CALL(*dataInterfaceMockPtr, write(_, _))
175cf0b9752SBrandon Kim .WillOnce(Return(wrongWriteSize));
176cf0b9752SBrandon Kim EXPECT_THROW(
177cf0b9752SBrandon Kim try {
178cf0b9752SBrandon Kim bufferImpl->updateReadPtr(0);
179cf0b9752SBrandon Kim } catch (const std::runtime_error& e) {
180cf0b9752SBrandon Kim EXPECT_STREQ(
181cf0b9752SBrandon Kim e.what(),
182271d2313SBrandon Kim "[updateReadPtr] Wrote '1' bytes, instead of expected '3'");
183cf0b9752SBrandon Kim throw;
184cf0b9752SBrandon Kim },
185cf0b9752SBrandon Kim std::runtime_error);
186cf0b9752SBrandon Kim }
187cf0b9752SBrandon Kim
TEST_F(BufferTest,BufferUpdateReadPtrPass)188cf0b9752SBrandon Kim TEST_F(BufferTest, BufferUpdateReadPtrPass)
189cf0b9752SBrandon Kim {
190271d2313SBrandon Kim constexpr size_t expectedWriteSize = 3;
191271d2313SBrandon Kim constexpr uint8_t expectedBmcReadPtrOffset = 0x21;
192271d2313SBrandon Kim // Check that we truncate the highest 24bits
193cf0b9752SBrandon Kim const uint32_t testNewReadPtr = 0x99881234;
194271d2313SBrandon Kim const std::vector<uint8_t> expectedReadPtr{0x34, 0x12, 0x88};
195cf0b9752SBrandon Kim
196cf0b9752SBrandon Kim EXPECT_CALL(*dataInterfaceMockPtr, write(expectedBmcReadPtrOffset,
197cf0b9752SBrandon Kim ElementsAreArray(expectedReadPtr)))
198cf0b9752SBrandon Kim .WillOnce(Return(expectedWriteSize));
199cf0b9752SBrandon Kim EXPECT_NO_THROW(bufferImpl->updateReadPtr(testNewReadPtr));
200c49284b6SBrandon Kim
201c49284b6SBrandon Kim auto cachedHeader = bufferImpl->getCachedBufferHeader();
202271d2313SBrandon Kim EXPECT_EQ(boost::endian::little_to_native(cachedHeader.bmcReadPtr),
203271d2313SBrandon Kim 0x881234);
204c49284b6SBrandon Kim }
205c49284b6SBrandon Kim
TEST_F(BufferTest,BufferUpdateBmcFlagsFail)206c49284b6SBrandon Kim TEST_F(BufferTest, BufferUpdateBmcFlagsFail)
207c49284b6SBrandon Kim {
208c49284b6SBrandon Kim // Return write size that is not 4 which is sizeof(little_uint32_t)
209c49284b6SBrandon Kim constexpr size_t wrongWriteSize = 1;
210c49284b6SBrandon Kim EXPECT_CALL(*dataInterfaceMockPtr, write(_, _))
211c49284b6SBrandon Kim .WillOnce(Return(wrongWriteSize));
212c49284b6SBrandon Kim EXPECT_THROW(
213c49284b6SBrandon Kim try {
214c49284b6SBrandon Kim bufferImpl->updateBmcFlags(static_cast<uint32_t>(BmcFlags::ready));
215c49284b6SBrandon Kim } catch (const std::runtime_error& e) {
216c49284b6SBrandon Kim EXPECT_STREQ(
217c49284b6SBrandon Kim e.what(),
218c49284b6SBrandon Kim "[updateBmcFlags] Wrote '1' bytes, instead of expected '4'");
219c49284b6SBrandon Kim throw;
220c49284b6SBrandon Kim },
221c49284b6SBrandon Kim std::runtime_error);
222c49284b6SBrandon Kim }
223c49284b6SBrandon Kim
TEST_F(BufferTest,BufferUpdateBmcFlagsPass)224c49284b6SBrandon Kim TEST_F(BufferTest, BufferUpdateBmcFlagsPass)
225c49284b6SBrandon Kim {
226c49284b6SBrandon Kim constexpr size_t expectedWriteSize = 4;
227271d2313SBrandon Kim constexpr uint8_t expectedBmcReadPtrOffset = 0x1d;
228c49284b6SBrandon Kim const std::vector<uint8_t> expectedNewBmcFlagsVector{0x04, 0x0, 0x0, 0x00};
229c49284b6SBrandon Kim
230c49284b6SBrandon Kim EXPECT_CALL(*dataInterfaceMockPtr,
231c49284b6SBrandon Kim write(expectedBmcReadPtrOffset,
232c49284b6SBrandon Kim ElementsAreArray(expectedNewBmcFlagsVector)))
233c49284b6SBrandon Kim .WillOnce(Return(expectedWriteSize));
234c49284b6SBrandon Kim EXPECT_NO_THROW(
235c49284b6SBrandon Kim bufferImpl->updateBmcFlags(static_cast<uint32_t>(BmcFlags::ready)));
236c49284b6SBrandon Kim
237c49284b6SBrandon Kim auto cachedHeader = bufferImpl->getCachedBufferHeader();
238c49284b6SBrandon Kim EXPECT_EQ(boost::endian::little_to_native(cachedHeader.bmcFlags),
239c49284b6SBrandon Kim static_cast<uint32_t>(BmcFlags::ready));
240cf0b9752SBrandon Kim }
241cf0b9752SBrandon Kim
TEST_F(BufferTest,GetMaxOffsetQueueSizeFail)24282ab8320SBrandon Kim TEST_F(BufferTest, GetMaxOffsetQueueSizeFail)
24382ab8320SBrandon Kim {
24482ab8320SBrandon Kim InSequence s;
24582ab8320SBrandon Kim static constexpr size_t wrongQueueSize = testQueueSize - 1;
24682ab8320SBrandon Kim EXPECT_CALL(*dataInterfaceMockPtr, getMemoryRegionSize())
24782ab8320SBrandon Kim .WillOnce(Return(testRegionSize));
24882ab8320SBrandon Kim const std::vector<uint8_t> emptyArray(wrongQueueSize, 0);
24982ab8320SBrandon Kim EXPECT_CALL(*dataInterfaceMockPtr, write(0, ElementsAreArray(emptyArray)))
25082ab8320SBrandon Kim .WillOnce(Return(wrongQueueSize));
25182ab8320SBrandon Kim
25282ab8320SBrandon Kim EXPECT_CALL(*dataInterfaceMockPtr, write(0, _))
25382ab8320SBrandon Kim .WillOnce(Return(bufferHeaderSize));
2541a64356fSPatrick Williams EXPECT_NO_THROW(
2551a64356fSPatrick Williams bufferImpl->initialize(testBmcInterfaceVersion, wrongQueueSize,
2561a64356fSPatrick Williams testUeRegionSize, testMagicNumber));
25782ab8320SBrandon Kim EXPECT_THROW(
25882ab8320SBrandon Kim try {
25982ab8320SBrandon Kim bufferImpl->getMaxOffset();
26082ab8320SBrandon Kim } catch (const std::runtime_error& e) {
26182ab8320SBrandon Kim EXPECT_STREQ(e.what(),
26282ab8320SBrandon Kim "[getMaxOffset] runtime queueSize '511' did not match "
26382ab8320SBrandon Kim "compile-time queueSize '512'. This indicates that the"
26482ab8320SBrandon Kim " buffer was corrupted");
26582ab8320SBrandon Kim throw;
26682ab8320SBrandon Kim },
26782ab8320SBrandon Kim std::runtime_error);
26882ab8320SBrandon Kim }
26982ab8320SBrandon Kim
TEST_F(BufferTest,GetMaxOffsetUeRegionSizeFail)27082ab8320SBrandon Kim TEST_F(BufferTest, GetMaxOffsetUeRegionSizeFail)
27182ab8320SBrandon Kim {
27282ab8320SBrandon Kim InSequence s;
27382ab8320SBrandon Kim EXPECT_CALL(*dataInterfaceMockPtr, getMemoryRegionSize())
27482ab8320SBrandon Kim .WillOnce(Return(testRegionSize));
27582ab8320SBrandon Kim const std::vector<uint8_t> emptyArray(testQueueSize, 0);
27682ab8320SBrandon Kim EXPECT_CALL(*dataInterfaceMockPtr, write(0, ElementsAreArray(emptyArray)))
27782ab8320SBrandon Kim .WillOnce(Return(testQueueSize));
27882ab8320SBrandon Kim
27982ab8320SBrandon Kim EXPECT_CALL(*dataInterfaceMockPtr, write(0, _))
28082ab8320SBrandon Kim .WillOnce(Return(bufferHeaderSize));
2811a64356fSPatrick Williams EXPECT_NO_THROW(
2821a64356fSPatrick Williams bufferImpl->initialize(testBmcInterfaceVersion, testQueueSize,
2831a64356fSPatrick Williams testUeRegionSize + 1, testMagicNumber));
28482ab8320SBrandon Kim EXPECT_THROW(
28582ab8320SBrandon Kim try {
28682ab8320SBrandon Kim bufferImpl->getMaxOffset();
28782ab8320SBrandon Kim } catch (const std::runtime_error& e) {
28882ab8320SBrandon Kim EXPECT_STREQ(
28982ab8320SBrandon Kim e.what(),
29082ab8320SBrandon Kim "[getMaxOffset] runtime ueRegionSize '81' did not match "
29182ab8320SBrandon Kim "compile-time ueRegionSize '80'. This indicates that the"
29282ab8320SBrandon Kim " buffer was corrupted");
29382ab8320SBrandon Kim throw;
29482ab8320SBrandon Kim },
29582ab8320SBrandon Kim std::runtime_error);
29682ab8320SBrandon Kim }
29782ab8320SBrandon Kim
TEST_F(BufferTest,GetOffsetUeRegionSizeFail)29882ab8320SBrandon Kim TEST_F(BufferTest, GetOffsetUeRegionSizeFail)
29982ab8320SBrandon Kim {
30082ab8320SBrandon Kim InSequence s;
30182ab8320SBrandon Kim EXPECT_CALL(*dataInterfaceMockPtr, getMemoryRegionSize())
30282ab8320SBrandon Kim .WillOnce(Return(testRegionSize));
30382ab8320SBrandon Kim const std::vector<uint8_t> emptyArray(testQueueSize, 0);
30482ab8320SBrandon Kim EXPECT_CALL(*dataInterfaceMockPtr, write(0, ElementsAreArray(emptyArray)))
30582ab8320SBrandon Kim .WillOnce(Return(testQueueSize));
30682ab8320SBrandon Kim
30782ab8320SBrandon Kim EXPECT_CALL(*dataInterfaceMockPtr, write(0, _))
30882ab8320SBrandon Kim .WillOnce(Return(bufferHeaderSize));
3091a64356fSPatrick Williams EXPECT_NO_THROW(
3101a64356fSPatrick Williams bufferImpl->initialize(testBmcInterfaceVersion, testQueueSize,
3111a64356fSPatrick Williams testUeRegionSize - 1, testMagicNumber));
31282ab8320SBrandon Kim EXPECT_THROW(
31382ab8320SBrandon Kim try {
31482ab8320SBrandon Kim bufferImpl->getQueueOffset();
31582ab8320SBrandon Kim } catch (const std::runtime_error& e) {
31682ab8320SBrandon Kim EXPECT_STREQ(
31782ab8320SBrandon Kim e.what(),
31882ab8320SBrandon Kim "[getQueueOffset] runtime ueRegionSize '79' did not match "
31982ab8320SBrandon Kim "compile-time ueRegionSize '80'. This indicates that the"
32082ab8320SBrandon Kim " buffer was corrupted");
32182ab8320SBrandon Kim throw;
32282ab8320SBrandon Kim },
32382ab8320SBrandon Kim std::runtime_error);
32482ab8320SBrandon Kim }
32582ab8320SBrandon Kim
3269836cfa6SBrandon Kim class BufferWraparoundReadTest : public BufferTest
3279836cfa6SBrandon Kim {
3289836cfa6SBrandon Kim protected:
BufferWraparoundReadTest()3299836cfa6SBrandon Kim BufferWraparoundReadTest()
3309836cfa6SBrandon Kim {
3314662b1bdSBrandon Kim initializeFuncMock();
3324662b1bdSBrandon Kim }
initializeFuncMock()3334662b1bdSBrandon Kim void initializeFuncMock()
3344662b1bdSBrandon Kim {
3359836cfa6SBrandon Kim // Initialize the memory and the cachedBufferHeader
3369836cfa6SBrandon Kim InSequence s;
3379836cfa6SBrandon Kim EXPECT_CALL(*dataInterfaceMockPtr, getMemoryRegionSize())
3389836cfa6SBrandon Kim .WillOnce(Return(testRegionSize));
3393def3c8eSBrandon Kim const std::vector<uint8_t> emptyArray(testQueueSize, 0);
3409836cfa6SBrandon Kim EXPECT_CALL(*dataInterfaceMockPtr,
3419836cfa6SBrandon Kim write(0, ElementsAreArray(emptyArray)))
3423def3c8eSBrandon Kim .WillOnce(Return(testQueueSize));
3439836cfa6SBrandon Kim
3444662b1bdSBrandon Kim EXPECT_CALL(*dataInterfaceMockPtr, write(0, _))
3459836cfa6SBrandon Kim .WillOnce(Return(bufferHeaderSize));
3461a64356fSPatrick Williams EXPECT_NO_THROW(
3471a64356fSPatrick Williams bufferImpl->initialize(testBmcInterfaceVersion, testQueueSize,
3481a64356fSPatrick Williams testUeRegionSize, testMagicNumber));
3499836cfa6SBrandon Kim }
350271d2313SBrandon Kim static constexpr size_t expectedWriteSize = 3;
351271d2313SBrandon Kim static constexpr uint8_t expectedBmcReadPtrOffset = 0x21;
3529836cfa6SBrandon Kim static constexpr size_t expectedqueueOffset = 0x30 + testUeRegionSize;
3534662b1bdSBrandon Kim
3541a64356fSPatrick Williams static constexpr size_t testMaxOffset =
3551a64356fSPatrick Williams testQueueSize - testUeRegionSize - sizeof(struct CircularBufferHeader);
3564662b1bdSBrandon Kim uint8_t* testInitializationHeaderPtr =
3574662b1bdSBrandon Kim reinterpret_cast<uint8_t*>(&testInitializationHeader);
3589836cfa6SBrandon Kim };
3599836cfa6SBrandon Kim
TEST_F(BufferWraparoundReadTest,GetMaxOffsetPassTest)36082ab8320SBrandon Kim TEST_F(BufferWraparoundReadTest, GetMaxOffsetPassTest)
3613def3c8eSBrandon Kim {
3623def3c8eSBrandon Kim EXPECT_EQ(bufferImpl->getMaxOffset(), testMaxOffset);
3633def3c8eSBrandon Kim }
3643def3c8eSBrandon Kim
TEST_F(BufferWraparoundReadTest,GetQueueOffsetPassTest)36582ab8320SBrandon Kim TEST_F(BufferWraparoundReadTest, GetQueueOffsetPassTest)
36682ab8320SBrandon Kim {
36782ab8320SBrandon Kim EXPECT_EQ(bufferImpl->getQueueOffset(),
36882ab8320SBrandon Kim bufferHeaderSize + testUeRegionSize);
36982ab8320SBrandon Kim }
37082ab8320SBrandon Kim
TEST_F(BufferWraparoundReadTest,ParamsTooBigFail)37135d4335eSBrandon Kim TEST_F(BufferWraparoundReadTest, ParamsTooBigFail)
3729836cfa6SBrandon Kim {
3739836cfa6SBrandon Kim InSequence s;
3743def3c8eSBrandon Kim size_t tooBigOffset = testMaxOffset + 1;
3759836cfa6SBrandon Kim EXPECT_THROW(
3769836cfa6SBrandon Kim try {
37735d4335eSBrandon Kim bufferImpl->wraparoundRead(tooBigOffset, /* length */ 1);
3789836cfa6SBrandon Kim } catch (const std::runtime_error& e) {
37926660e9bSBrandon Kim EXPECT_STREQ(
38026660e9bSBrandon Kim e.what(),
3813def3c8eSBrandon Kim "[wraparoundRead] relativeOffset '385' was bigger than maxOffset '384'");
38235d4335eSBrandon Kim throw;
38335d4335eSBrandon Kim },
38435d4335eSBrandon Kim std::runtime_error);
38535d4335eSBrandon Kim
3863def3c8eSBrandon Kim size_t tooBigLength = testMaxOffset + 1;
38735d4335eSBrandon Kim EXPECT_THROW(
38835d4335eSBrandon Kim try {
38935d4335eSBrandon Kim bufferImpl->wraparoundRead(/* relativeOffset */ 0, tooBigLength);
39035d4335eSBrandon Kim } catch (const std::runtime_error& e) {
3913def3c8eSBrandon Kim EXPECT_STREQ(e.what(), "[wraparoundRead] length '385' was bigger "
3923def3c8eSBrandon Kim "than maxOffset '384'");
3939836cfa6SBrandon Kim throw;
3949836cfa6SBrandon Kim },
3959836cfa6SBrandon Kim std::runtime_error);
3969836cfa6SBrandon Kim }
3979836cfa6SBrandon Kim
TEST_F(BufferWraparoundReadTest,NoWrapAroundReadFails)39835d4335eSBrandon Kim TEST_F(BufferWraparoundReadTest, NoWrapAroundReadFails)
3999836cfa6SBrandon Kim {
4009836cfa6SBrandon Kim InSequence s;
40135d4335eSBrandon Kim size_t testLength = 0x10;
40235d4335eSBrandon Kim size_t testOffset = 0x20;
40335d4335eSBrandon Kim
40435d4335eSBrandon Kim // Fail the first read
40535d4335eSBrandon Kim std::vector<std::uint8_t> shortTestBytesRead(testLength - 1);
40635d4335eSBrandon Kim EXPECT_CALL(*dataInterfaceMockPtr,
40735d4335eSBrandon Kim read(testOffset + expectedqueueOffset, testLength))
40835d4335eSBrandon Kim .WillOnce(Return(shortTestBytesRead));
40935d4335eSBrandon Kim
4109836cfa6SBrandon Kim EXPECT_THROW(
4119836cfa6SBrandon Kim try {
41235d4335eSBrandon Kim bufferImpl->wraparoundRead(testOffset, testLength);
4139836cfa6SBrandon Kim } catch (const std::runtime_error& e) {
41435d4335eSBrandon Kim EXPECT_STREQ(e.what(),
41535d4335eSBrandon Kim "[wraparoundRead] Read '15' which was not the "
41635d4335eSBrandon Kim "requested length of '16'");
4179836cfa6SBrandon Kim throw;
4189836cfa6SBrandon Kim },
4199836cfa6SBrandon Kim std::runtime_error);
4209836cfa6SBrandon Kim }
4219836cfa6SBrandon Kim
TEST_F(BufferWraparoundReadTest,NoWrapAroundReadPass)4229836cfa6SBrandon Kim TEST_F(BufferWraparoundReadTest, NoWrapAroundReadPass)
4239836cfa6SBrandon Kim {
4249836cfa6SBrandon Kim InSequence s;
4259836cfa6SBrandon Kim size_t testLength = 0x10;
42635d4335eSBrandon Kim size_t testOffset = 0x20;
4279836cfa6SBrandon Kim
4289836cfa6SBrandon Kim // Successfully read all the requested length without a wrap around
4299836cfa6SBrandon Kim std::vector<std::uint8_t> testBytesRead(testLength);
43035d4335eSBrandon Kim EXPECT_CALL(*dataInterfaceMockPtr,
43135d4335eSBrandon Kim read(testOffset + expectedqueueOffset, testLength))
4329836cfa6SBrandon Kim .WillOnce(Return(testBytesRead));
4339836cfa6SBrandon Kim
4349836cfa6SBrandon Kim // Call to updateReadPtr is triggered
4359836cfa6SBrandon Kim const std::vector<uint8_t> expectedReadPtr{
436271d2313SBrandon Kim static_cast<uint8_t>(testOffset + testLength), 0x0, 0x0};
4379836cfa6SBrandon Kim EXPECT_CALL(*dataInterfaceMockPtr, write(expectedBmcReadPtrOffset,
4389836cfa6SBrandon Kim ElementsAreArray(expectedReadPtr)))
4399836cfa6SBrandon Kim .WillOnce(Return(expectedWriteSize));
4409836cfa6SBrandon Kim
4419836cfa6SBrandon Kim EXPECT_THAT(bufferImpl->wraparoundRead(testOffset, testLength),
4429836cfa6SBrandon Kim ElementsAreArray(testBytesRead));
44335d4335eSBrandon Kim struct CircularBufferHeader cachedBufferHeader =
44435d4335eSBrandon Kim bufferImpl->getCachedBufferHeader();
44535d4335eSBrandon Kim // The bmcReadPtr should have been updated
44635d4335eSBrandon Kim EXPECT_EQ(boost::endian::little_to_native(cachedBufferHeader.bmcReadPtr),
44735d4335eSBrandon Kim testOffset + testLength);
4489836cfa6SBrandon Kim }
4499836cfa6SBrandon Kim
TEST_F(BufferWraparoundReadTest,WrapAroundReadFails)4509836cfa6SBrandon Kim TEST_F(BufferWraparoundReadTest, WrapAroundReadFails)
4519836cfa6SBrandon Kim {
4529836cfa6SBrandon Kim InSequence s;
4539836cfa6SBrandon Kim size_t testBytesLeft = 3;
4549836cfa6SBrandon Kim size_t testLength = 0x10;
4553def3c8eSBrandon Kim size_t testOffset = testMaxOffset - (testLength - testBytesLeft);
4569836cfa6SBrandon Kim
45735d4335eSBrandon Kim // Read until the end of the queue
4589836cfa6SBrandon Kim std::vector<std::uint8_t> testBytesReadShort(testLength - testBytesLeft);
45935d4335eSBrandon Kim EXPECT_CALL(*dataInterfaceMockPtr, read(testOffset + expectedqueueOffset,
46035d4335eSBrandon Kim testLength - testBytesLeft))
4619836cfa6SBrandon Kim .WillOnce(Return(testBytesReadShort));
4629836cfa6SBrandon Kim
4639836cfa6SBrandon Kim // Read 1 byte short after wraparound
4649836cfa6SBrandon Kim std::vector<std::uint8_t> testBytesLeftReadShort(testBytesLeft - 1);
4659836cfa6SBrandon Kim EXPECT_CALL(*dataInterfaceMockPtr, read(expectedqueueOffset, testBytesLeft))
4669836cfa6SBrandon Kim .WillOnce(Return(testBytesLeftReadShort));
4679836cfa6SBrandon Kim
4689836cfa6SBrandon Kim EXPECT_THROW(
4699836cfa6SBrandon Kim try {
4709836cfa6SBrandon Kim bufferImpl->wraparoundRead(testOffset, testLength);
4719836cfa6SBrandon Kim } catch (const std::runtime_error& e) {
47235d4335eSBrandon Kim EXPECT_STREQ(
47335d4335eSBrandon Kim e.what(),
47435d4335eSBrandon Kim "[wraparoundRead] Buffer wrapped around but read '2' which was "
47535d4335eSBrandon Kim "not the requested lenght of '3'");
4769836cfa6SBrandon Kim throw;
4779836cfa6SBrandon Kim },
4789836cfa6SBrandon Kim std::runtime_error);
4799836cfa6SBrandon Kim }
4809836cfa6SBrandon Kim
TEST_F(BufferWraparoundReadTest,WrapAroundReadPasses)4819836cfa6SBrandon Kim TEST_F(BufferWraparoundReadTest, WrapAroundReadPasses)
4829836cfa6SBrandon Kim {
4839836cfa6SBrandon Kim InSequence s;
4849836cfa6SBrandon Kim size_t testBytesLeft = 3;
4859836cfa6SBrandon Kim size_t testLength = 0x10;
4863def3c8eSBrandon Kim size_t testOffset = testMaxOffset - (testLength - testBytesLeft);
4879836cfa6SBrandon Kim
48835d4335eSBrandon Kim // Read to the end of the queue
4899836cfa6SBrandon Kim std::vector<std::uint8_t> testBytesReadFirst{16, 15, 14, 13, 12, 11, 10,
4909836cfa6SBrandon Kim 9, 8, 7, 6, 5, 4};
49135d4335eSBrandon Kim EXPECT_CALL(*dataInterfaceMockPtr, read(testOffset + expectedqueueOffset,
49235d4335eSBrandon Kim testLength - testBytesLeft))
4939836cfa6SBrandon Kim .WillOnce(Return(testBytesReadFirst));
4949836cfa6SBrandon Kim
4959836cfa6SBrandon Kim std::vector<std::uint8_t> testBytesReadSecond{3, 2, 1};
4969836cfa6SBrandon Kim EXPECT_CALL(*dataInterfaceMockPtr, read(expectedqueueOffset, testBytesLeft))
4979836cfa6SBrandon Kim .WillOnce(Return(testBytesReadSecond));
4989836cfa6SBrandon Kim
4999836cfa6SBrandon Kim // Call to updateReadPtr is triggered
5009836cfa6SBrandon Kim const std::vector<uint8_t> expectedReadPtr{
501271d2313SBrandon Kim static_cast<uint8_t>(testBytesLeft), 0x0, 0x0};
5029836cfa6SBrandon Kim EXPECT_CALL(*dataInterfaceMockPtr, write(expectedBmcReadPtrOffset,
5039836cfa6SBrandon Kim ElementsAreArray(expectedReadPtr)))
5049836cfa6SBrandon Kim .WillOnce(Return(expectedWriteSize));
5059836cfa6SBrandon Kim
5069836cfa6SBrandon Kim std::vector<std::uint8_t> expectedBytes = {16, 15, 14, 13, 12, 11, 10, 9,
5079836cfa6SBrandon Kim 8, 7, 6, 5, 4, 3, 2, 1};
5089836cfa6SBrandon Kim EXPECT_THAT(bufferImpl->wraparoundRead(testOffset, testLength),
5099836cfa6SBrandon Kim ElementsAreArray(expectedBytes));
51035d4335eSBrandon Kim struct CircularBufferHeader cachedBufferHeader =
51135d4335eSBrandon Kim bufferImpl->getCachedBufferHeader();
51235d4335eSBrandon Kim // The bmcReadPtr should have been updated to reflect the wraparound
51335d4335eSBrandon Kim EXPECT_EQ(boost::endian::little_to_native(cachedBufferHeader.bmcReadPtr),
51435d4335eSBrandon Kim testBytesLeft);
5159836cfa6SBrandon Kim }
5169836cfa6SBrandon Kim
TEST_F(BufferWraparoundReadTest,WrapAroundCornerCasePass)5174662b1bdSBrandon Kim TEST_F(BufferWraparoundReadTest, WrapAroundCornerCasePass)
5184662b1bdSBrandon Kim {
5194662b1bdSBrandon Kim InSequence s;
5204662b1bdSBrandon Kim size_t testBytesLeft = 0;
5214662b1bdSBrandon Kim size_t testLength = 4;
5223def3c8eSBrandon Kim size_t testOffset = testMaxOffset - (testLength - testBytesLeft);
5234662b1bdSBrandon Kim
5244662b1bdSBrandon Kim // Read to the very end of the queue
5254662b1bdSBrandon Kim std::vector<std::uint8_t> testBytes{4, 3, 2, 1};
5264662b1bdSBrandon Kim EXPECT_CALL(*dataInterfaceMockPtr,
5274662b1bdSBrandon Kim read(testOffset + expectedqueueOffset, testLength))
5284662b1bdSBrandon Kim .WillOnce(Return(testBytes));
5294662b1bdSBrandon Kim
5304662b1bdSBrandon Kim // Call to updateReadPtr is triggered, since we read to the very end of the
5314662b1bdSBrandon Kim // buffer, update the readPtr up around to 0
532271d2313SBrandon Kim const std::vector<uint8_t> expectedReadPtr{0x0, 0x0, 0x0};
5334662b1bdSBrandon Kim EXPECT_CALL(*dataInterfaceMockPtr, write(expectedBmcReadPtrOffset,
5344662b1bdSBrandon Kim ElementsAreArray(expectedReadPtr)))
5354662b1bdSBrandon Kim .WillOnce(Return(expectedWriteSize));
5364662b1bdSBrandon Kim
5374662b1bdSBrandon Kim EXPECT_THAT(bufferImpl->wraparoundRead(testOffset, testLength),
5384662b1bdSBrandon Kim ElementsAreArray(testBytes));
5394662b1bdSBrandon Kim struct CircularBufferHeader cachedBufferHeader =
5404662b1bdSBrandon Kim bufferImpl->getCachedBufferHeader();
5414662b1bdSBrandon Kim // The bmcReadPtr should have been updated to reflect the wraparound
5424662b1bdSBrandon Kim EXPECT_EQ(boost::endian::little_to_native(cachedBufferHeader.bmcReadPtr),
5434662b1bdSBrandon Kim 0);
5444662b1bdSBrandon Kim }
5454662b1bdSBrandon Kim
54640ce08e1SBrandon Kim class BufferEntryTest : public BufferWraparoundReadTest
5477bac2d69SBrandon Kim {
5487bac2d69SBrandon Kim protected:
BufferEntryTest()54940ce08e1SBrandon Kim BufferEntryTest()
5507bac2d69SBrandon Kim {
5517bac2d69SBrandon Kim testEntryHeader.sequenceId = testSequenceId;
5527bac2d69SBrandon Kim testEntryHeader.entrySize = testEntrySize;
5537bac2d69SBrandon Kim testEntryHeader.checksum = testChecksum;
5547bac2d69SBrandon Kim testEntryHeader.rdeCommandType = testRdeCommandType;
5557bac2d69SBrandon Kim }
55640ce08e1SBrandon Kim ~BufferEntryTest() override = default;
5577bac2d69SBrandon Kim
wraparoundReadMock(const uint32_t relativeOffset,std::span<std::uint8_t> expetedBytesOutput)55835d4335eSBrandon Kim void wraparoundReadMock(const uint32_t relativeOffset,
55935d4335eSBrandon Kim std::span<std::uint8_t> expetedBytesOutput)
56035d4335eSBrandon Kim {
56135d4335eSBrandon Kim InSequence s;
5623def3c8eSBrandon Kim const uint32_t queueSizeToQueueEnd = testMaxOffset - relativeOffset;
56335d4335eSBrandon Kim
56435d4335eSBrandon Kim // This will wrap, split the read mocks in 2
56535d4335eSBrandon Kim if (expetedBytesOutput.size() > queueSizeToQueueEnd)
56635d4335eSBrandon Kim {
56735d4335eSBrandon Kim EXPECT_CALL(*dataInterfaceMockPtr, read(_, _))
56835d4335eSBrandon Kim .WillOnce(Return(std::vector<std::uint8_t>(
56935d4335eSBrandon Kim expetedBytesOutput.begin(),
57035d4335eSBrandon Kim expetedBytesOutput.begin() + queueSizeToQueueEnd)));
57135d4335eSBrandon Kim EXPECT_CALL(*dataInterfaceMockPtr, read(_, _))
57235d4335eSBrandon Kim .WillOnce(Return(std::vector<std::uint8_t>(
57335d4335eSBrandon Kim expetedBytesOutput.begin() + queueSizeToQueueEnd,
57435d4335eSBrandon Kim expetedBytesOutput.end())));
57535d4335eSBrandon Kim }
57635d4335eSBrandon Kim else
5777bac2d69SBrandon Kim {
5787bac2d69SBrandon Kim EXPECT_CALL(*dataInterfaceMockPtr, read(_, _))
5797bac2d69SBrandon Kim .WillOnce(Return(std::vector<std::uint8_t>(
5807bac2d69SBrandon Kim expetedBytesOutput.begin(), expetedBytesOutput.end())));
58135d4335eSBrandon Kim }
5827bac2d69SBrandon Kim
5837bac2d69SBrandon Kim EXPECT_CALL(*dataInterfaceMockPtr, write(_, _))
5847bac2d69SBrandon Kim .WillOnce(Return(expectedWriteSize));
5857bac2d69SBrandon Kim }
5867bac2d69SBrandon Kim
5877bac2d69SBrandon Kim static constexpr size_t entryHeaderSize = sizeof(struct QueueEntryHeader);
5887bac2d69SBrandon Kim static constexpr uint16_t testSequenceId = 0;
5897bac2d69SBrandon Kim static constexpr uint16_t testEntrySize = 0x20;
5907bac2d69SBrandon Kim static constexpr uint8_t testRdeCommandType = 0x01;
591f0e4adc9SBrandon Kim // Calculated checksum for the header
592f0e4adc9SBrandon Kim static constexpr uint8_t testChecksum =
593f0e4adc9SBrandon Kim (testSequenceId ^ testEntrySize ^ testRdeCommandType);
594613ba537SBrandon Kim size_t testOffset = 0x0;
5957bac2d69SBrandon Kim
596*c20d1216SPatrick Williams struct QueueEntryHeader testEntryHeader{};
5977bac2d69SBrandon Kim };
5987bac2d69SBrandon Kim
TEST_F(BufferEntryTest,ReadEntryHeaderPass)59940ce08e1SBrandon Kim TEST_F(BufferEntryTest, ReadEntryHeaderPass)
6007bac2d69SBrandon Kim {
6017bac2d69SBrandon Kim uint8_t* testEntryHeaderPtr = reinterpret_cast<uint8_t*>(&testEntryHeader);
6027bac2d69SBrandon Kim std::vector<uint8_t> testEntryHeaderVector(
6037bac2d69SBrandon Kim testEntryHeaderPtr, testEntryHeaderPtr + entryHeaderSize);
60435d4335eSBrandon Kim wraparoundReadMock(testOffset, testEntryHeaderVector);
605613ba537SBrandon Kim EXPECT_EQ(bufferImpl->readEntryHeader(), testEntryHeader);
60635d4335eSBrandon Kim // Check the bmcReadPtr
60735d4335eSBrandon Kim struct CircularBufferHeader cachedBufferHeader =
60835d4335eSBrandon Kim bufferImpl->getCachedBufferHeader();
60935d4335eSBrandon Kim EXPECT_EQ(boost::endian::little_to_native(cachedBufferHeader.bmcReadPtr),
61035d4335eSBrandon Kim testOffset + testEntryHeaderVector.size());
6117bac2d69SBrandon Kim }
6127bac2d69SBrandon Kim
TEST_F(BufferEntryTest,ReadEntryChecksumFail)61340ce08e1SBrandon Kim TEST_F(BufferEntryTest, ReadEntryChecksumFail)
61440ce08e1SBrandon Kim {
61540ce08e1SBrandon Kim InSequence s;
616f0e4adc9SBrandon Kim std::vector<uint8_t> testEntryVector(testEntrySize);
61740ce08e1SBrandon Kim // Offset the checksum by 1
618f0e4adc9SBrandon Kim testEntryHeader.checksum += 1;
61940ce08e1SBrandon Kim uint8_t* testEntryHeaderPtr = reinterpret_cast<uint8_t*>(&testEntryHeader);
62040ce08e1SBrandon Kim std::vector<uint8_t> testEntryHeaderVector(
62140ce08e1SBrandon Kim testEntryHeaderPtr, testEntryHeaderPtr + entryHeaderSize);
62235d4335eSBrandon Kim wraparoundReadMock(testOffset, testEntryHeaderVector);
62335d4335eSBrandon Kim wraparoundReadMock(testOffset + entryHeaderSize, testEntryVector);
62440ce08e1SBrandon Kim EXPECT_THROW(
625613ba537SBrandon Kim try { bufferImpl->readEntry(); } catch (const std::runtime_error& e) {
626f0e4adc9SBrandon Kim // Calculation: testChecksum (0x21) XOR (0x22) = 3
62740ce08e1SBrandon Kim EXPECT_STREQ(e.what(),
628f0e4adc9SBrandon Kim "[readEntry] Checksum was '3', expected '0'");
62940ce08e1SBrandon Kim throw;
63040ce08e1SBrandon Kim },
63140ce08e1SBrandon Kim std::runtime_error);
63240ce08e1SBrandon Kim }
63340ce08e1SBrandon Kim
TEST_F(BufferEntryTest,ReadEntryPassWraparound)634613ba537SBrandon Kim TEST_F(BufferEntryTest, ReadEntryPassWraparound)
63540ce08e1SBrandon Kim {
63640ce08e1SBrandon Kim InSequence s;
637f0e4adc9SBrandon Kim // We expect this will bump checksum up by "testEntrySize" = 0xff ^ 0xff ...
638f0e4adc9SBrandon Kim // (20 times) = 0 therefore leave the checksum as is
63935d4335eSBrandon Kim std::vector<uint8_t> testEntryVector(testEntrySize, 0xff);
64040ce08e1SBrandon Kim uint8_t* testEntryHeaderPtr = reinterpret_cast<uint8_t*>(&testEntryHeader);
64140ce08e1SBrandon Kim std::vector<uint8_t> testEntryHeaderVector(
64240ce08e1SBrandon Kim testEntryHeaderPtr, testEntryHeaderPtr + entryHeaderSize);
643613ba537SBrandon Kim // Set testOffset so that we can test the wraparound here at the header and
644613ba537SBrandon Kim // update the readPtr
6453def3c8eSBrandon Kim testOffset = testMaxOffset - 1;
646613ba537SBrandon Kim EXPECT_CALL(*dataInterfaceMockPtr, write(expectedBmcReadPtrOffset, _))
647613ba537SBrandon Kim .WillOnce(Return(expectedWriteSize));
648613ba537SBrandon Kim EXPECT_NO_THROW(bufferImpl->updateReadPtr(testOffset));
649613ba537SBrandon Kim
65035d4335eSBrandon Kim wraparoundReadMock(testOffset, testEntryHeaderVector);
65135d4335eSBrandon Kim wraparoundReadMock(testOffset + entryHeaderSize, testEntryVector);
65240ce08e1SBrandon Kim
65340ce08e1SBrandon Kim EntryPair testedEntryPair;
654613ba537SBrandon Kim EXPECT_NO_THROW(testedEntryPair = bufferImpl->readEntry());
65540ce08e1SBrandon Kim EXPECT_EQ(testedEntryPair.first, testEntryHeader);
65640ce08e1SBrandon Kim EXPECT_THAT(testedEntryPair.second, ElementsAreArray(testEntryVector));
65735d4335eSBrandon Kim struct CircularBufferHeader cachedBufferHeader =
65835d4335eSBrandon Kim bufferImpl->getCachedBufferHeader();
65935d4335eSBrandon Kim // The bmcReadPtr should have been updated to reflect the wraparound
66035d4335eSBrandon Kim EXPECT_EQ(boost::endian::little_to_native(cachedBufferHeader.bmcReadPtr),
661613ba537SBrandon Kim entryHeaderSize + testEntrySize - 1);
662613ba537SBrandon Kim
663613ba537SBrandon Kim // Set testOffset so that we can test the wraparound here as well on our
664613ba537SBrandon Kim // second read for the entry (by 1 byte)
6653def3c8eSBrandon Kim testOffset = testMaxOffset - entryHeaderSize - 1;
666613ba537SBrandon Kim EXPECT_CALL(*dataInterfaceMockPtr, write(expectedBmcReadPtrOffset, _))
667613ba537SBrandon Kim .WillOnce(Return(expectedWriteSize));
668613ba537SBrandon Kim EXPECT_NO_THROW(bufferImpl->updateReadPtr(testOffset));
669613ba537SBrandon Kim
670613ba537SBrandon Kim wraparoundReadMock(testOffset, testEntryHeaderVector);
671613ba537SBrandon Kim wraparoundReadMock(testOffset + entryHeaderSize, testEntryVector);
672613ba537SBrandon Kim
673613ba537SBrandon Kim EXPECT_NO_THROW(testedEntryPair = bufferImpl->readEntry());
674613ba537SBrandon Kim EXPECT_EQ(testedEntryPair.first, testEntryHeader);
675613ba537SBrandon Kim EXPECT_THAT(testedEntryPair.second, ElementsAreArray(testEntryVector));
676613ba537SBrandon Kim cachedBufferHeader = bufferImpl->getCachedBufferHeader();
677613ba537SBrandon Kim // The bmcReadPtr should have been updated to reflect the wraparound
678613ba537SBrandon Kim EXPECT_EQ(boost::endian::little_to_native(cachedBufferHeader.bmcReadPtr),
67935d4335eSBrandon Kim testEntrySize - 1);
68040ce08e1SBrandon Kim }
68140ce08e1SBrandon Kim
6824662b1bdSBrandon Kim class BufferReadErrorLogsTest : public BufferEntryTest
6834662b1bdSBrandon Kim {
6844662b1bdSBrandon Kim protected:
6854662b1bdSBrandon Kim BufferReadErrorLogsTest() = default;
6864662b1bdSBrandon Kim
6874662b1bdSBrandon Kim uint8_t* testEntryHeaderPtr = reinterpret_cast<uint8_t*>(&testEntryHeader);
6884662b1bdSBrandon Kim size_t entryAndHeaderSize = entryHeaderSize + testEntrySize;
6894662b1bdSBrandon Kim };
6904662b1bdSBrandon Kim
TEST_F(BufferReadErrorLogsTest,PtrsTooBigFail)6914662b1bdSBrandon Kim TEST_F(BufferReadErrorLogsTest, PtrsTooBigFail)
6924662b1bdSBrandon Kim {
6934662b1bdSBrandon Kim InSequence s;
6944662b1bdSBrandon Kim // Set the biosWritePtr too big
6954662b1bdSBrandon Kim testInitializationHeader.biosWritePtr =
6963def3c8eSBrandon Kim boost::endian::native_to_little((testMaxOffset + 1));
6974662b1bdSBrandon Kim initializeFuncMock();
6984662b1bdSBrandon Kim
6994662b1bdSBrandon Kim EXPECT_CALL(*dataInterfaceMockPtr, read(0, bufferHeaderSize))
7001a64356fSPatrick Williams .WillOnce(Return(std::vector<uint8_t>(
7011a64356fSPatrick Williams testInitializationHeaderPtr,
7021a64356fSPatrick Williams testInitializationHeaderPtr + bufferHeaderSize)));
7034662b1bdSBrandon Kim EXPECT_THROW(
7044662b1bdSBrandon Kim try {
7054662b1bdSBrandon Kim bufferImpl->readErrorLogs();
7064662b1bdSBrandon Kim } catch (const std::runtime_error& e) {
7074662b1bdSBrandon Kim EXPECT_STREQ(e.what(),
7083def3c8eSBrandon Kim "[readErrorLogs] currentBiosWritePtr was '385' "
7093def3c8eSBrandon Kim "which was bigger than maxOffset '384'");
7104662b1bdSBrandon Kim throw;
7114662b1bdSBrandon Kim },
7124662b1bdSBrandon Kim std::runtime_error);
7134662b1bdSBrandon Kim
7144662b1bdSBrandon Kim // Reset the biosWritePtr and set the bmcReadPtr too big
7154662b1bdSBrandon Kim testInitializationHeader.biosWritePtr = 0;
7164662b1bdSBrandon Kim initializeFuncMock();
7174662b1bdSBrandon Kim testInitializationHeader.bmcReadPtr =
7183def3c8eSBrandon Kim boost::endian::native_to_little((testMaxOffset + 1));
7194662b1bdSBrandon Kim initializeFuncMock();
7204662b1bdSBrandon Kim
7214662b1bdSBrandon Kim EXPECT_CALL(*dataInterfaceMockPtr, read(0, bufferHeaderSize))
7221a64356fSPatrick Williams .WillOnce(Return(std::vector<uint8_t>(
7231a64356fSPatrick Williams testInitializationHeaderPtr,
7241a64356fSPatrick Williams testInitializationHeaderPtr + bufferHeaderSize)));
7254662b1bdSBrandon Kim EXPECT_THROW(
7264662b1bdSBrandon Kim try {
7274662b1bdSBrandon Kim bufferImpl->readErrorLogs();
7284662b1bdSBrandon Kim } catch (const std::runtime_error& e) {
7293def3c8eSBrandon Kim EXPECT_STREQ(e.what(), "[readErrorLogs] currentReadPtr was '385' "
7303def3c8eSBrandon Kim "which was bigger than maxOffset '384'");
7314662b1bdSBrandon Kim throw;
7324662b1bdSBrandon Kim },
7334662b1bdSBrandon Kim std::runtime_error);
7344662b1bdSBrandon Kim }
7354662b1bdSBrandon Kim
TEST_F(BufferReadErrorLogsTest,IdenticalPtrsPass)7364662b1bdSBrandon Kim TEST_F(BufferReadErrorLogsTest, IdenticalPtrsPass)
7374662b1bdSBrandon Kim {
7384662b1bdSBrandon Kim EXPECT_CALL(*dataInterfaceMockPtr, read(0, bufferHeaderSize))
7391a64356fSPatrick Williams .WillOnce(Return(std::vector<uint8_t>(
7401a64356fSPatrick Williams testInitializationHeaderPtr,
7411a64356fSPatrick Williams testInitializationHeaderPtr + bufferHeaderSize)));
7424662b1bdSBrandon Kim EXPECT_NO_THROW(bufferImpl->readErrorLogs());
7434662b1bdSBrandon Kim }
7444662b1bdSBrandon Kim
TEST_F(BufferReadErrorLogsTest,NoWraparoundPass)7454662b1bdSBrandon Kim TEST_F(BufferReadErrorLogsTest, NoWraparoundPass)
7464662b1bdSBrandon Kim {
7474662b1bdSBrandon Kim InSequence s;
7484662b1bdSBrandon Kim // Set the biosWritePtr to 1 entryHeader + entry size
7494662b1bdSBrandon Kim testInitializationHeader.biosWritePtr =
7504662b1bdSBrandon Kim boost::endian::native_to_little((entryAndHeaderSize));
7514662b1bdSBrandon Kim initializeFuncMock();
7524662b1bdSBrandon Kim EXPECT_CALL(*dataInterfaceMockPtr, read(0, bufferHeaderSize))
7531a64356fSPatrick Williams .WillOnce(Return(std::vector<uint8_t>(
7541a64356fSPatrick Williams testInitializationHeaderPtr,
7551a64356fSPatrick Williams testInitializationHeaderPtr + bufferHeaderSize)));
7564662b1bdSBrandon Kim std::vector<uint8_t> testEntryHeaderVector(
7574662b1bdSBrandon Kim testEntryHeaderPtr, testEntryHeaderPtr + entryHeaderSize);
7584662b1bdSBrandon Kim std::vector<uint8_t> testEntryVector(testEntrySize);
7594662b1bdSBrandon Kim wraparoundReadMock(/*relativeOffset=*/0, testEntryHeaderVector);
7604662b1bdSBrandon Kim wraparoundReadMock(/*relativeOffset=*/0 + entryHeaderSize, testEntryVector);
7614662b1bdSBrandon Kim
7624662b1bdSBrandon Kim std::vector<EntryPair> entryPairs;
7634662b1bdSBrandon Kim EXPECT_NO_THROW(entryPairs = bufferImpl->readErrorLogs());
7644662b1bdSBrandon Kim
7654662b1bdSBrandon Kim // Check that we only read one entryPair and that the content is correct
7661a3dc60dSBrandon Kim EXPECT_EQ(entryPairs.size(), 1U);
7674662b1bdSBrandon Kim EXPECT_EQ(entryPairs[0].first, testEntryHeader);
7684662b1bdSBrandon Kim EXPECT_THAT(entryPairs[0].second, ElementsAreArray(testEntryVector));
7694662b1bdSBrandon Kim }
7704662b1bdSBrandon Kim
TEST_F(BufferReadErrorLogsTest,WraparoundMultiplEntryPass)7714662b1bdSBrandon Kim TEST_F(BufferReadErrorLogsTest, WraparoundMultiplEntryPass)
7724662b1bdSBrandon Kim {
7734662b1bdSBrandon Kim InSequence s;
7744662b1bdSBrandon Kim // Set the bmcReadPtr to 1 entryHeader + entry size from the "end" exactly
7753def3c8eSBrandon Kim uint32_t entryAndHeaderSizeAwayFromEnd = testMaxOffset - entryAndHeaderSize;
7764662b1bdSBrandon Kim testInitializationHeader.bmcReadPtr =
7774662b1bdSBrandon Kim boost::endian::native_to_little(entryAndHeaderSizeAwayFromEnd);
7784662b1bdSBrandon Kim // Set the biosWritePtr to 1 entryHeader + entry size from the "beginning"
7794662b1bdSBrandon Kim testInitializationHeader.biosWritePtr = entryAndHeaderSize;
7804662b1bdSBrandon Kim initializeFuncMock();
7814662b1bdSBrandon Kim EXPECT_CALL(*dataInterfaceMockPtr, read(0, bufferHeaderSize))
7821a64356fSPatrick Williams .WillOnce(Return(std::vector<uint8_t>(
7831a64356fSPatrick Williams testInitializationHeaderPtr,
7841a64356fSPatrick Williams testInitializationHeaderPtr + bufferHeaderSize)));
7854662b1bdSBrandon Kim
7864662b1bdSBrandon Kim std::vector<uint8_t> testEntryHeaderVector(
7874662b1bdSBrandon Kim testEntryHeaderPtr, testEntryHeaderPtr + entryHeaderSize);
7884662b1bdSBrandon Kim std::vector<uint8_t> testEntryVector(testEntrySize);
7894662b1bdSBrandon Kim wraparoundReadMock(/*relativeOffset=*/entryAndHeaderSizeAwayFromEnd,
7904662b1bdSBrandon Kim testEntryHeaderVector);
7914662b1bdSBrandon Kim wraparoundReadMock(/*relativeOffset=*/entryAndHeaderSizeAwayFromEnd +
7924662b1bdSBrandon Kim entryHeaderSize,
7934662b1bdSBrandon Kim testEntryVector);
7944662b1bdSBrandon Kim wraparoundReadMock(/*relativeOffset=*/0 + entryAndHeaderSize,
7954662b1bdSBrandon Kim testEntryHeaderVector);
7964662b1bdSBrandon Kim wraparoundReadMock(/*relativeOffset=*/0 + entryAndHeaderSize +
7974662b1bdSBrandon Kim entryHeaderSize,
7984662b1bdSBrandon Kim testEntryVector);
7994662b1bdSBrandon Kim
8004662b1bdSBrandon Kim std::vector<EntryPair> entryPairs;
8014662b1bdSBrandon Kim EXPECT_NO_THROW(entryPairs = bufferImpl->readErrorLogs());
8024662b1bdSBrandon Kim
8034662b1bdSBrandon Kim // Check that we only read one entryPair and that the content is correct
8044662b1bdSBrandon Kim EXPECT_EQ(entryPairs.size(), 2);
8054662b1bdSBrandon Kim EXPECT_EQ(entryPairs[0].first, testEntryHeader);
8064662b1bdSBrandon Kim EXPECT_EQ(entryPairs[1].first, testEntryHeader);
8074662b1bdSBrandon Kim EXPECT_THAT(entryPairs[0].second, ElementsAreArray(testEntryVector));
8084662b1bdSBrandon Kim EXPECT_THAT(entryPairs[1].second, ElementsAreArray(testEntryVector));
8094662b1bdSBrandon Kim }
8104662b1bdSBrandon Kim
TEST_F(BufferReadErrorLogsTest,WraparoundMismatchingPtrsFail)8114662b1bdSBrandon Kim TEST_F(BufferReadErrorLogsTest, WraparoundMismatchingPtrsFail)
8124662b1bdSBrandon Kim {
8134662b1bdSBrandon Kim InSequence s;
8144662b1bdSBrandon Kim testInitializationHeader.bmcReadPtr = boost::endian::native_to_little(0);
8154662b1bdSBrandon Kim // Make the biosWritePtr intentially 1 smaller than expected
8164662b1bdSBrandon Kim testInitializationHeader.biosWritePtr =
8174662b1bdSBrandon Kim boost::endian::native_to_little(entryAndHeaderSize - 1);
8184662b1bdSBrandon Kim initializeFuncMock();
8194662b1bdSBrandon Kim EXPECT_CALL(*dataInterfaceMockPtr, read(0, bufferHeaderSize))
8201a64356fSPatrick Williams .WillOnce(Return(std::vector<uint8_t>(
8211a64356fSPatrick Williams testInitializationHeaderPtr,
8221a64356fSPatrick Williams testInitializationHeaderPtr + bufferHeaderSize)));
8234662b1bdSBrandon Kim
8244662b1bdSBrandon Kim std::vector<uint8_t> testEntryHeaderVector(
8254662b1bdSBrandon Kim testEntryHeaderPtr, testEntryHeaderPtr + entryHeaderSize);
8264662b1bdSBrandon Kim std::vector<uint8_t> testEntryVector(testEntrySize);
8274662b1bdSBrandon Kim wraparoundReadMock(/*relativeOffset=*/0, testEntryHeaderVector);
8284662b1bdSBrandon Kim wraparoundReadMock(/*relativeOffset=*/0 + entryHeaderSize, testEntryVector);
8294662b1bdSBrandon Kim
8304662b1bdSBrandon Kim EXPECT_THROW(
8314662b1bdSBrandon Kim try {
8324662b1bdSBrandon Kim bufferImpl->readErrorLogs();
8334662b1bdSBrandon Kim } catch (const std::runtime_error& e) {
8344662b1bdSBrandon Kim EXPECT_STREQ(
8354662b1bdSBrandon Kim e.what(),
8364662b1bdSBrandon Kim "[readErrorLogs] biosWritePtr '37' and bmcReaddPtr '38' "
8374662b1bdSBrandon Kim "are not identical after reading through all the logs");
8384662b1bdSBrandon Kim throw;
8394662b1bdSBrandon Kim },
8404662b1bdSBrandon Kim std::runtime_error);
8414662b1bdSBrandon Kim }
8424662b1bdSBrandon Kim
843fcbc3db1SBrandon Kim } // namespace
844fcbc3db1SBrandon Kim } // namespace bios_bmc_smm_error_logger
845