Add overflow flag checking
This is to ensure that we check for and flag buffer overflow flag from
the BIOS.
The logic should be:
```
1. BIOS_switch ^ BMC_switch == 0 → No overflow incident
a. CONTINUE
2. BIOS_switch ^ BMC_switch == 1 → an unlogged overflow incident has occurred
b. Log the overflow incident
c. Toggle the BMC overflow flag
```
Tested: Added unit test
Signed-off-by: Brandon Kim <brandonkim@google.com>
Change-Id: I25c50a8de93900480413389d7d2a89b9be4b5643
diff --git a/include/buffer.hpp b/include/buffer.hpp
index 06e282f..95154de 100644
--- a/include/buffer.hpp
+++ b/include/buffer.hpp
@@ -109,6 +109,11 @@
virtual std::vector<uint8_t> readUeLogFromReservedRegion() = 0;
/**
+ * Check for overflow and ackknolwedge if not acked yet
+ */
+ virtual bool checkForOverflowAndAcknowledge() = 0;
+
+ /**
* Read the buffer header from shared buffer
*/
virtual void readBufferHeader() = 0;
@@ -191,6 +196,7 @@
uint16_t ueRegionSize,
const std::array<uint32_t, 4>& magicNumber) override;
std::vector<uint8_t> readUeLogFromReservedRegion() override;
+ bool checkForOverflowAndAcknowledge() override;
void readBufferHeader() override;
struct CircularBufferHeader getCachedBufferHeader() const override;
void updateReadPtr(const uint32_t newReadPtr) override;
diff --git a/src/buffer.cpp b/src/buffer.cpp
index 0254cac..3af1125 100644
--- a/src/buffer.cpp
+++ b/src/buffer.cpp
@@ -269,6 +269,36 @@
currentUeRegionSize, ueLogData.size()));
}
+bool BufferImpl::checkForOverflowAndAcknowledge()
+{
+ // Ensure cachedBufferHeader is up-to-date
+ readBufferHeader();
+
+ uint32_t biosSideFlags =
+ boost::endian::little_to_native(cachedBufferHeader.biosFlags);
+ uint32_t bmcSideFlags =
+ boost::endian::little_to_native(cachedBufferHeader.bmcFlags);
+
+ // Design: (BIOS_switch ^ BMC_switch) & BIT1 == BIT1 -> unlogged overflow
+ // This means if the overflow bit differs, there's an
+ // unacknowledged overflow.
+ if ((biosSideFlags ^ bmcSideFlags) &
+ static_cast<uint32_t>(BufferFlags::overflow))
+ {
+ // Overflow incident has occurred and BMC has not acknowledged it.
+ // Toggle BMC's view of the overflow flag to acknowledge.
+ uint32_t newBmcFlags =
+ bmcSideFlags ^ static_cast<uint32_t>(BufferFlags::overflow);
+ updateBmcFlags(newBmcFlags);
+
+ // Overflow was detected and acknowledged
+ return true;
+ }
+
+ // No new overflow incident or already acknowledged
+ return false;
+}
+
EntryPair BufferImpl::readEntry()
{
struct QueueEntryHeader entryHeader = readEntryHeader();
diff --git a/src/main.cpp b/src/main.cpp
index 4465185..eb15677 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -79,6 +79,13 @@
bufferInterface->updateBmcFlags(newBmcFlags);
}
+ if (bufferInterface->checkForOverflowAndAcknowledge())
+ {
+ stdplus::print(
+ stdout,
+ "[WARN] Buffer overflow had occured and has been acked\n");
+ }
+
std::vector<EntryPair> entryPairs = bufferInterface->readErrorLogs();
for (const auto& [entryHeader, entry] : entryPairs)
{
diff --git a/test/buffer_test.cpp b/test/buffer_test.cpp
index 675be79..d6f355a 100644
--- a/test/buffer_test.cpp
+++ b/test/buffer_test.cpp
@@ -420,6 +420,60 @@
std::runtime_error);
}
+TEST_F(BufferTest, CheckOverflow_NotPresentDueToFlags)
+{
+ struct CircularBufferHeader header = testInitializationHeader;
+ // Flags are the same, so no new overflow
+ header.biosFlags = boost::endian::native_to_little<uint32_t>(
+ static_cast<uint32_t>(BufferFlags::overflow));
+ header.bmcFlags = boost::endian::native_to_little<uint32_t>(
+ static_cast<uint32_t>(BufferFlags::overflow));
+
+ uint8_t* headerPtr = reinterpret_cast<uint8_t*>(&header);
+ std::vector<uint8_t> headerBytes(headerPtr, headerPtr + bufferHeaderSize);
+ EXPECT_CALL(*dataInterfaceMockPtr, read(0, bufferHeaderSize))
+ .WillOnce(Return(headerBytes));
+
+ bool overflowDetected = bufferImpl->checkForOverflowAndAcknowledge();
+ ASSERT_FALSE(overflowDetected);
+}
+
+TEST_F(BufferTest, CheckOverflow_PresentAndAcknowledged)
+{
+ struct CircularBufferHeader header = testInitializationHeader;
+ header.biosFlags = boost::endian::native_to_little<uint32_t>(
+ static_cast<uint32_t>(BufferFlags::overflow));
+ header.bmcFlags =
+ boost::endian::native_to_little<uint32_t>(0); // BIOS set, BMC not yet
+
+ uint8_t* headerPtr = reinterpret_cast<uint8_t*>(&header);
+ std::vector<uint8_t> headerBytes(headerPtr, headerPtr + bufferHeaderSize);
+ EXPECT_CALL(*dataInterfaceMockPtr, read(0, bufferHeaderSize))
+ .WillOnce(Return(headerBytes));
+
+ uint32_t expectedNewBmcFlags =
+ static_cast<uint32_t>(BufferFlags::overflow); // BMC toggles its bit
+ little_uint32_t littleExpectedNewBmcFlags =
+ boost::endian::native_to_little(expectedNewBmcFlags);
+ uint8_t* flagPtr = reinterpret_cast<uint8_t*>(&littleExpectedNewBmcFlags);
+ std::vector<uint8_t> expectedFlagWrite(flagPtr,
+ flagPtr + sizeof(little_uint32_t));
+ constexpr uint8_t bmcFlagsOffset =
+ offsetof(struct CircularBufferHeader, bmcFlags);
+
+ EXPECT_CALL(*dataInterfaceMockPtr,
+ write(bmcFlagsOffset, ElementsAreArray(expectedFlagWrite)))
+ .WillOnce(Return(sizeof(little_uint32_t)));
+
+ bool overflowDetected = bufferImpl->checkForOverflowAndAcknowledge();
+ ASSERT_TRUE(overflowDetected);
+
+ struct CircularBufferHeader updatedCachedHeader =
+ bufferImpl->getCachedBufferHeader();
+ EXPECT_EQ(boost::endian::little_to_native(updatedCachedHeader.bmcFlags),
+ expectedNewBmcFlags);
+}
+
class BufferWraparoundReadTest : public BufferTest
{
protected: