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/src/buffer.cpp b/src/buffer.cpp
index 836049f..278f8cf 100644
--- a/src/buffer.cpp
+++ b/src/buffer.cpp
@@ -78,7 +78,7 @@
{
size_t headerSize = sizeof(struct CircularBufferHeader);
std::vector<uint8_t> bytesRead =
- dataInterface->read(/* offset */ 0, headerSize);
+ dataInterface->read(/*offset=*/0, headerSize);
if (bytesRead.size() != headerSize)
{
@@ -166,6 +166,12 @@
bytesRead.size(), numBytesToReadTillQueueEnd));
}
size_t updatedReadPtr = relativeOffset + numBytesToReadTillQueueEnd;
+ if (updatedReadPtr == queueSize)
+ {
+ // If we read all the way up to the end of the queue, we need to
+ // manually wrap the updateReadPtr around to 0
+ updatedReadPtr = 0;
+ }
// If there are any more bytes to be read beyond the buffer, wrap around and
// read from the beginning of the buffer (offset by the queueOffset)
@@ -226,4 +232,71 @@
return {entryHeader, entry};
}
+std::vector<EntryPair> BufferImpl::readErrorLogs()
+{
+ // Reading the buffer header will update the cachedBufferHeader
+ readBufferHeader();
+
+ const size_t queueSize =
+ boost::endian::little_to_native(cachedBufferHeader.queueSize);
+ size_t currentBiosWritePtr =
+ boost::endian::little_to_native(cachedBufferHeader.biosWritePtr);
+ if (currentBiosWritePtr > queueSize)
+ {
+ throw std::runtime_error(fmt::format(
+ "[readErrorLogs] currentBiosWritePtr was '{}' which was bigger "
+ "than queueSize '{}'",
+ currentBiosWritePtr, queueSize));
+ }
+ size_t currentReadPtr =
+ boost::endian::little_to_native(cachedBufferHeader.bmcReadPtr);
+ if (currentReadPtr > queueSize)
+ {
+ throw std::runtime_error(fmt::format(
+ "[readErrorLogs] currentReadPtr was '{}' which was bigger "
+ "than queueSize '{}'",
+ currentReadPtr, queueSize));
+ }
+
+ size_t bytesToRead;
+ if (currentBiosWritePtr == currentReadPtr)
+ {
+ // No new payload was detected, return an empty vector gracefully
+ return {};
+ }
+
+ if (currentBiosWritePtr > currentReadPtr)
+ {
+ // Simply subtract in this case
+ bytesToRead = currentBiosWritePtr - currentReadPtr;
+ }
+ else
+ {
+ // Calculate the bytes to the "end" (QueueSize - ReadPtr) +
+ // bytes to read from the "beginning" (0 + WritePtr)
+ bytesToRead = (queueSize - currentReadPtr) + currentBiosWritePtr;
+ }
+
+ size_t byteRead = 0;
+ std::vector<EntryPair> entryPairs;
+ while (byteRead < bytesToRead)
+ {
+ EntryPair entryPair = readEntry(currentReadPtr);
+ byteRead += sizeof(struct QueueEntryHeader) + entryPair.second.size();
+ entryPairs.push_back(entryPair);
+
+ // Note: readEntry() will update cachedBufferHeader.bmcReadPtr
+ currentReadPtr =
+ boost::endian::little_to_native(cachedBufferHeader.bmcReadPtr);
+ }
+ if (currentBiosWritePtr != currentReadPtr)
+ {
+ throw std::runtime_error(fmt::format(
+ "[readErrorLogs] biosWritePtr '{}' and bmcReaddPtr '{}' "
+ "are not identical after reading through all the logs",
+ currentBiosWritePtr, currentReadPtr));
+ }
+ return entryPairs;
+}
+
} // namespace bios_bmc_smm_error_logger