buffer: Implement "readErrorLogs"
This is the API that will be called by the main to read all of the error
logs. Found a cornercase in wraparoundRead, so added a unit test to
guard it as well.
Tested:
Unit tested and tested on a real HW (with the following changes)
Signed-off-by: Brandon Kim <brandonkim@google.com>
Change-Id: I94cd3a2f53ee7da2c145b751c1c3b5989f4c5b23
diff --git a/test/buffer_test.cpp b/test/buffer_test.cpp
index 6f886f0..577e322 100644
--- a/test/buffer_test.cpp
+++ b/test/buffer_test.cpp
@@ -210,6 +210,10 @@
protected:
BufferWraparoundReadTest()
{
+ initializeFuncMock();
+ }
+ void initializeFuncMock()
+ {
// Initialize the memory and the cachedBufferHeader
InSequence s;
EXPECT_CALL(*dataInterfaceMockPtr, getMemoryRegionSize())
@@ -221,11 +225,7 @@
write(0, ElementsAreArray(emptyArray)))
.WillOnce(Return(testProposedBufferSize));
- uint8_t* testInitializationHeaderPtr =
- reinterpret_cast<uint8_t*>(&testInitializationHeader);
- EXPECT_CALL(*dataInterfaceMockPtr,
- write(0, ElementsAreArray(testInitializationHeaderPtr,
- bufferHeaderSize)))
+ EXPECT_CALL(*dataInterfaceMockPtr, write(0, _))
.WillOnce(Return(bufferHeaderSize));
EXPECT_NO_THROW(bufferImpl->initialize(testBmcInterfaceVersion,
testQueueSize, testUeRegionSize,
@@ -234,6 +234,9 @@
static constexpr size_t expectedWriteSize = 2;
static constexpr uint8_t expectedBmcReadPtrOffset = 0x20;
static constexpr size_t expectedqueueOffset = 0x30 + testUeRegionSize;
+
+ uint8_t* testInitializationHeaderPtr =
+ reinterpret_cast<uint8_t*>(&testInitializationHeader);
};
TEST_F(BufferWraparoundReadTest, ParamsTooBigFail)
@@ -383,6 +386,35 @@
testBytesLeft);
}
+TEST_F(BufferWraparoundReadTest, WrapAroundCornerCasePass)
+{
+ InSequence s;
+ size_t testBytesLeft = 0;
+ size_t testLength = 4;
+ size_t testOffset = testQueueSize - (testLength - testBytesLeft);
+
+ // Read to the very end of the queue
+ std::vector<std::uint8_t> testBytes{4, 3, 2, 1};
+ EXPECT_CALL(*dataInterfaceMockPtr,
+ read(testOffset + expectedqueueOffset, testLength))
+ .WillOnce(Return(testBytes));
+
+ // Call to updateReadPtr is triggered, since we read to the very end of the
+ // buffer, update the readPtr up around to 0
+ const std::vector<uint8_t> expectedReadPtr{0x0, 0x0};
+ EXPECT_CALL(*dataInterfaceMockPtr, write(expectedBmcReadPtrOffset,
+ ElementsAreArray(expectedReadPtr)))
+ .WillOnce(Return(expectedWriteSize));
+
+ EXPECT_THAT(bufferImpl->wraparoundRead(testOffset, testLength),
+ ElementsAreArray(testBytes));
+ struct CircularBufferHeader cachedBufferHeader =
+ bufferImpl->getCachedBufferHeader();
+ // The bmcReadPtr should have been updated to reflect the wraparound
+ EXPECT_EQ(boost::endian::little_to_native(cachedBufferHeader.bmcReadPtr),
+ 0);
+}
+
class BufferEntryTest : public BufferWraparoundReadTest
{
protected:
@@ -500,5 +532,166 @@
testEntrySize - 1);
}
+class BufferReadErrorLogsTest : public BufferEntryTest
+{
+ protected:
+ BufferReadErrorLogsTest() = default;
+
+ uint8_t* testEntryHeaderPtr = reinterpret_cast<uint8_t*>(&testEntryHeader);
+ size_t entryAndHeaderSize = entryHeaderSize + testEntrySize;
+};
+
+TEST_F(BufferReadErrorLogsTest, PtrsTooBigFail)
+{
+ InSequence s;
+ // Set the biosWritePtr too big
+ testInitializationHeader.biosWritePtr =
+ boost::endian::native_to_little((testQueueSize + 1));
+ initializeFuncMock();
+
+ EXPECT_CALL(*dataInterfaceMockPtr, read(0, bufferHeaderSize))
+ .WillOnce(Return(std::vector<uint8_t>(testInitializationHeaderPtr,
+ testInitializationHeaderPtr +
+ bufferHeaderSize)));
+ EXPECT_THROW(
+ try {
+ bufferImpl->readErrorLogs();
+ } catch (const std::runtime_error& e) {
+ EXPECT_STREQ(e.what(),
+ "[readErrorLogs] currentBiosWritePtr was '257' "
+ "which was bigger than queueSize '256'");
+ throw;
+ },
+ std::runtime_error);
+
+ // Reset the biosWritePtr and set the bmcReadPtr too big
+ testInitializationHeader.biosWritePtr = 0;
+ initializeFuncMock();
+ testInitializationHeader.bmcReadPtr =
+ boost::endian::native_to_little((testQueueSize + 1));
+ initializeFuncMock();
+
+ EXPECT_CALL(*dataInterfaceMockPtr, read(0, bufferHeaderSize))
+ .WillOnce(Return(std::vector<uint8_t>(testInitializationHeaderPtr,
+ testInitializationHeaderPtr +
+ bufferHeaderSize)));
+ EXPECT_THROW(
+ try {
+ bufferImpl->readErrorLogs();
+ } catch (const std::runtime_error& e) {
+ EXPECT_STREQ(e.what(), "[readErrorLogs] currentReadPtr was '257' "
+ "which was bigger than queueSize '256'");
+ throw;
+ },
+ std::runtime_error);
+}
+
+TEST_F(BufferReadErrorLogsTest, IdenticalPtrsPass)
+{
+ EXPECT_CALL(*dataInterfaceMockPtr, read(0, bufferHeaderSize))
+ .WillOnce(Return(std::vector<uint8_t>(testInitializationHeaderPtr,
+ testInitializationHeaderPtr +
+ bufferHeaderSize)));
+ EXPECT_NO_THROW(bufferImpl->readErrorLogs());
+}
+
+TEST_F(BufferReadErrorLogsTest, NoWraparoundPass)
+{
+ InSequence s;
+ // Set the biosWritePtr to 1 entryHeader + entry size
+ testInitializationHeader.biosWritePtr =
+ boost::endian::native_to_little((entryAndHeaderSize));
+ initializeFuncMock();
+ EXPECT_CALL(*dataInterfaceMockPtr, read(0, bufferHeaderSize))
+ .WillOnce(Return(std::vector<uint8_t>(testInitializationHeaderPtr,
+ testInitializationHeaderPtr +
+ bufferHeaderSize)));
+ std::vector<uint8_t> testEntryHeaderVector(
+ testEntryHeaderPtr, testEntryHeaderPtr + entryHeaderSize);
+ std::vector<uint8_t> testEntryVector(testEntrySize);
+ wraparoundReadMock(/*relativeOffset=*/0, testEntryHeaderVector);
+ wraparoundReadMock(/*relativeOffset=*/0 + entryHeaderSize, testEntryVector);
+
+ std::vector<EntryPair> entryPairs;
+ EXPECT_NO_THROW(entryPairs = bufferImpl->readErrorLogs());
+
+ // Check that we only read one entryPair and that the content is correct
+ EXPECT_EQ(entryPairs.size(), 1);
+ EXPECT_EQ(entryPairs[0].first, testEntryHeader);
+ EXPECT_THAT(entryPairs[0].second, ElementsAreArray(testEntryVector));
+}
+
+TEST_F(BufferReadErrorLogsTest, WraparoundMultiplEntryPass)
+{
+ InSequence s;
+ // Set the bmcReadPtr to 1 entryHeader + entry size from the "end" exactly
+ uint32_t entryAndHeaderSizeAwayFromEnd = testQueueSize - entryAndHeaderSize;
+ testInitializationHeader.bmcReadPtr =
+ boost::endian::native_to_little(entryAndHeaderSizeAwayFromEnd);
+ // Set the biosWritePtr to 1 entryHeader + entry size from the "beginning"
+ testInitializationHeader.biosWritePtr = entryAndHeaderSize;
+ initializeFuncMock();
+ EXPECT_CALL(*dataInterfaceMockPtr, read(0, bufferHeaderSize))
+ .WillOnce(Return(std::vector<uint8_t>(testInitializationHeaderPtr,
+ testInitializationHeaderPtr +
+ bufferHeaderSize)));
+
+ std::vector<uint8_t> testEntryHeaderVector(
+ testEntryHeaderPtr, testEntryHeaderPtr + entryHeaderSize);
+ std::vector<uint8_t> testEntryVector(testEntrySize);
+ wraparoundReadMock(/*relativeOffset=*/entryAndHeaderSizeAwayFromEnd,
+ testEntryHeaderVector);
+ wraparoundReadMock(/*relativeOffset=*/entryAndHeaderSizeAwayFromEnd +
+ entryHeaderSize,
+ testEntryVector);
+ wraparoundReadMock(/*relativeOffset=*/0 + entryAndHeaderSize,
+ testEntryHeaderVector);
+ wraparoundReadMock(/*relativeOffset=*/0 + entryAndHeaderSize +
+ entryHeaderSize,
+ testEntryVector);
+
+ std::vector<EntryPair> entryPairs;
+ EXPECT_NO_THROW(entryPairs = bufferImpl->readErrorLogs());
+
+ // Check that we only read one entryPair and that the content is correct
+ EXPECT_EQ(entryPairs.size(), 2);
+ EXPECT_EQ(entryPairs[0].first, testEntryHeader);
+ EXPECT_EQ(entryPairs[1].first, testEntryHeader);
+ EXPECT_THAT(entryPairs[0].second, ElementsAreArray(testEntryVector));
+ EXPECT_THAT(entryPairs[1].second, ElementsAreArray(testEntryVector));
+}
+
+TEST_F(BufferReadErrorLogsTest, WraparoundMismatchingPtrsFail)
+{
+ InSequence s;
+ testInitializationHeader.bmcReadPtr = boost::endian::native_to_little(0);
+ // Make the biosWritePtr intentially 1 smaller than expected
+ testInitializationHeader.biosWritePtr =
+ boost::endian::native_to_little(entryAndHeaderSize - 1);
+ initializeFuncMock();
+ EXPECT_CALL(*dataInterfaceMockPtr, read(0, bufferHeaderSize))
+ .WillOnce(Return(std::vector<uint8_t>(testInitializationHeaderPtr,
+ testInitializationHeaderPtr +
+ bufferHeaderSize)));
+
+ std::vector<uint8_t> testEntryHeaderVector(
+ testEntryHeaderPtr, testEntryHeaderPtr + entryHeaderSize);
+ std::vector<uint8_t> testEntryVector(testEntrySize);
+ wraparoundReadMock(/*relativeOffset=*/0, testEntryHeaderVector);
+ wraparoundReadMock(/*relativeOffset=*/0 + entryHeaderSize, testEntryVector);
+
+ EXPECT_THROW(
+ try {
+ bufferImpl->readErrorLogs();
+ } catch (const std::runtime_error& e) {
+ EXPECT_STREQ(
+ e.what(),
+ "[readErrorLogs] biosWritePtr '37' and bmcReaddPtr '38' "
+ "are not identical after reading through all the logs");
+ throw;
+ },
+ std::runtime_error);
+}
+
} // namespace
} // namespace bios_bmc_smm_error_logger