182ab8320SBrandon Kim #include "config.h"
282ab8320SBrandon Kim
3fcbc3db1SBrandon Kim #include "buffer.hpp"
4fcbc3db1SBrandon Kim
5fcbc3db1SBrandon Kim #include "pci_handler.hpp"
6fcbc3db1SBrandon Kim
717ee1a93SBrandon Kim #include <boost/endian/arithmetic.hpp>
817ee1a93SBrandon Kim #include <boost/endian/conversion.hpp>
917ee1a93SBrandon Kim
1017ee1a93SBrandon Kim #include <algorithm>
11fcbc3db1SBrandon Kim #include <array>
12cf0b9752SBrandon Kim #include <cstddef>
13fcbc3db1SBrandon Kim #include <cstdint>
145de90619SPatrick Williams #include <format>
15fcbc3db1SBrandon Kim #include <memory>
1640ce08e1SBrandon Kim #include <numeric>
17fcbc3db1SBrandon Kim #include <span>
18fcbc3db1SBrandon Kim #include <vector>
19fcbc3db1SBrandon Kim
20fcbc3db1SBrandon Kim namespace bios_bmc_smm_error_logger
21fcbc3db1SBrandon Kim {
22fcbc3db1SBrandon Kim
BufferImpl(std::unique_ptr<DataInterface> dataInterface)23fcbc3db1SBrandon Kim BufferImpl::BufferImpl(std::unique_ptr<DataInterface> dataInterface) :
24fcbc3db1SBrandon Kim dataInterface(std::move(dataInterface)) {};
25fcbc3db1SBrandon Kim
initialize(uint32_t bmcInterfaceVersion,uint16_t queueSize,uint16_t ueRegionSize,const std::array<uint32_t,4> & magicNumber)26fcbc3db1SBrandon Kim void BufferImpl::initialize(uint32_t bmcInterfaceVersion, uint16_t queueSize,
27fcbc3db1SBrandon Kim uint16_t ueRegionSize,
28fcbc3db1SBrandon Kim const std::array<uint32_t, 4>& magicNumber)
29fcbc3db1SBrandon Kim {
30fcbc3db1SBrandon Kim const size_t memoryRegionSize = dataInterface->getMemoryRegionSize();
313def3c8eSBrandon Kim if (queueSize > memoryRegionSize)
3226660e9bSBrandon Kim {
335de90619SPatrick Williams throw std::runtime_error(std::format(
343def3c8eSBrandon Kim "[initialize] Proposed queue size '{}' is bigger than the "
3526660e9bSBrandon Kim "BMC's allocated MMIO region of '{}'",
363def3c8eSBrandon Kim queueSize, memoryRegionSize));
3726660e9bSBrandon Kim }
3826660e9bSBrandon Kim
3926660e9bSBrandon Kim // Initialize the whole buffer with 0x00
403def3c8eSBrandon Kim const std::vector<uint8_t> emptyVector(queueSize, 0);
41fcbc3db1SBrandon Kim size_t byteWritten = dataInterface->write(0, emptyVector);
423def3c8eSBrandon Kim if (byteWritten != queueSize)
43fcbc3db1SBrandon Kim {
44fcbc3db1SBrandon Kim throw std::runtime_error(
455de90619SPatrick Williams std::format("[initialize] Only erased '{}'", byteWritten));
46fcbc3db1SBrandon Kim }
47fcbc3db1SBrandon Kim
48fcbc3db1SBrandon Kim // Create an initial buffer header and write to it
49fcbc3db1SBrandon Kim struct CircularBufferHeader initializationHeader = {};
5017ee1a93SBrandon Kim initializationHeader.bmcInterfaceVersion =
5117ee1a93SBrandon Kim boost::endian::native_to_little(bmcInterfaceVersion);
5217ee1a93SBrandon Kim initializationHeader.queueSize = boost::endian::native_to_little(queueSize);
5317ee1a93SBrandon Kim initializationHeader.ueRegionSize =
5417ee1a93SBrandon Kim boost::endian::native_to_little(ueRegionSize);
5517ee1a93SBrandon Kim std::transform(magicNumber.begin(), magicNumber.end(),
5617ee1a93SBrandon Kim initializationHeader.magicNumber.begin(),
5717ee1a93SBrandon Kim [](uint32_t number) -> little_uint32_t {
5817ee1a93SBrandon Kim return boost::endian::native_to_little(number);
5917ee1a93SBrandon Kim });
60fcbc3db1SBrandon Kim
61fcbc3db1SBrandon Kim uint8_t* initializationHeaderPtr =
62fcbc3db1SBrandon Kim reinterpret_cast<uint8_t*>(&initializationHeader);
63fcbc3db1SBrandon Kim size_t initializationHeaderSize = sizeof(initializationHeader);
64fcbc3db1SBrandon Kim byteWritten = dataInterface->write(
65*1a64356fSPatrick Williams 0, std::span<const uint8_t>(
66*1a64356fSPatrick Williams initializationHeaderPtr,
67*1a64356fSPatrick Williams initializationHeaderPtr + initializationHeaderSize));
68fcbc3db1SBrandon Kim if (byteWritten != initializationHeaderSize)
69fcbc3db1SBrandon Kim {
705de90619SPatrick Williams throw std::runtime_error(std::format(
7126660e9bSBrandon Kim "[initialize] Only wrote '{}' bytes of the header", byteWritten));
72fcbc3db1SBrandon Kim }
7360cab57fSBrandon Kim cachedBufferHeader = initializationHeader;
74fcbc3db1SBrandon Kim }
75fcbc3db1SBrandon Kim
readBufferHeader()7617ee1a93SBrandon Kim void BufferImpl::readBufferHeader()
7717ee1a93SBrandon Kim {
7817ee1a93SBrandon Kim size_t headerSize = sizeof(struct CircularBufferHeader);
79*1a64356fSPatrick Williams std::vector<uint8_t> bytesRead =
80*1a64356fSPatrick Williams dataInterface->read(/*offset=*/0, headerSize);
8117ee1a93SBrandon Kim
8217ee1a93SBrandon Kim if (bytesRead.size() != headerSize)
8317ee1a93SBrandon Kim {
8417ee1a93SBrandon Kim throw std::runtime_error(
855de90619SPatrick Williams std::format("Buffer header read only read '{}', expected '{}'",
8617ee1a93SBrandon Kim bytesRead.size(), headerSize));
8717ee1a93SBrandon Kim }
8817ee1a93SBrandon Kim
8917ee1a93SBrandon Kim cachedBufferHeader =
9060cab57fSBrandon Kim *reinterpret_cast<struct CircularBufferHeader*>(bytesRead.data());
9117ee1a93SBrandon Kim };
9217ee1a93SBrandon Kim
getCachedBufferHeader() const9317ee1a93SBrandon Kim struct CircularBufferHeader BufferImpl::getCachedBufferHeader() const
9417ee1a93SBrandon Kim {
9517ee1a93SBrandon Kim return cachedBufferHeader;
9617ee1a93SBrandon Kim }
9717ee1a93SBrandon Kim
updateReadPtr(const uint32_t newReadPtr)98cf0b9752SBrandon Kim void BufferImpl::updateReadPtr(const uint32_t newReadPtr)
99cf0b9752SBrandon Kim {
100*1a64356fSPatrick Williams constexpr uint8_t bmcReadPtrOffset =
101*1a64356fSPatrick Williams offsetof(struct CircularBufferHeader, bmcReadPtr);
102cf0b9752SBrandon Kim
103271d2313SBrandon Kim little_uint24_t truncatedReadPtr =
104271d2313SBrandon Kim boost::endian::native_to_little(newReadPtr & 0xffffff);
105cf0b9752SBrandon Kim uint8_t* truncatedReadPtrPtr =
106cf0b9752SBrandon Kim reinterpret_cast<uint8_t*>(&truncatedReadPtr);
107cf0b9752SBrandon Kim
108cf0b9752SBrandon Kim size_t writtenSize = dataInterface->write(
109cf0b9752SBrandon Kim bmcReadPtrOffset, std::span<const uint8_t>{
110cf0b9752SBrandon Kim truncatedReadPtrPtr,
111271d2313SBrandon Kim truncatedReadPtrPtr + sizeof(truncatedReadPtr)});
112271d2313SBrandon Kim if (writtenSize != sizeof(truncatedReadPtr))
113cf0b9752SBrandon Kim {
1145de90619SPatrick Williams throw std::runtime_error(std::format(
115cf0b9752SBrandon Kim "[updateReadPtr] Wrote '{}' bytes, instead of expected '{}'",
116271d2313SBrandon Kim writtenSize, sizeof(truncatedReadPtr)));
117cf0b9752SBrandon Kim }
118cf0b9752SBrandon Kim cachedBufferHeader.bmcReadPtr = truncatedReadPtr;
119cf0b9752SBrandon Kim }
120cf0b9752SBrandon Kim
updateBmcFlags(const uint32_t newBmcFlag)121c49284b6SBrandon Kim void BufferImpl::updateBmcFlags(const uint32_t newBmcFlag)
122c49284b6SBrandon Kim {
123*1a64356fSPatrick Williams constexpr uint8_t bmcFlagsPtrOffset =
124*1a64356fSPatrick Williams offsetof(struct CircularBufferHeader, bmcFlags);
125c49284b6SBrandon Kim
126c49284b6SBrandon Kim little_uint32_t littleNewBmcFlag =
127c49284b6SBrandon Kim boost::endian::native_to_little(newBmcFlag);
128c49284b6SBrandon Kim uint8_t* littleNewBmcFlagPtr =
129c49284b6SBrandon Kim reinterpret_cast<uint8_t*>(&littleNewBmcFlag);
130c49284b6SBrandon Kim
131c49284b6SBrandon Kim size_t writtenSize = dataInterface->write(
132c49284b6SBrandon Kim bmcFlagsPtrOffset, std::span<const uint8_t>{
133c49284b6SBrandon Kim littleNewBmcFlagPtr,
134c49284b6SBrandon Kim littleNewBmcFlagPtr + sizeof(little_uint32_t)});
135c49284b6SBrandon Kim if (writtenSize != sizeof(little_uint32_t))
136c49284b6SBrandon Kim {
1375de90619SPatrick Williams throw std::runtime_error(std::format(
138c49284b6SBrandon Kim "[updateBmcFlags] Wrote '{}' bytes, instead of expected '{}'",
139c49284b6SBrandon Kim writtenSize, sizeof(little_uint32_t)));
140c49284b6SBrandon Kim }
141c49284b6SBrandon Kim cachedBufferHeader.bmcFlags = littleNewBmcFlag;
142c49284b6SBrandon Kim }
143c49284b6SBrandon Kim
wraparoundRead(const uint32_t relativeOffset,const uint32_t length)14435d4335eSBrandon Kim std::vector<uint8_t> BufferImpl::wraparoundRead(const uint32_t relativeOffset,
14535d4335eSBrandon Kim const uint32_t length)
1469836cfa6SBrandon Kim {
1473def3c8eSBrandon Kim const size_t maxOffset = getMaxOffset();
1489836cfa6SBrandon Kim
1493def3c8eSBrandon Kim if (relativeOffset > maxOffset)
15035d4335eSBrandon Kim {
15135d4335eSBrandon Kim throw std::runtime_error(
1525de90619SPatrick Williams std::format("[wraparoundRead] relativeOffset '{}' was bigger "
1533def3c8eSBrandon Kim "than maxOffset '{}'",
1543def3c8eSBrandon Kim relativeOffset, maxOffset));
15535d4335eSBrandon Kim }
1563def3c8eSBrandon Kim if (length > maxOffset)
1579836cfa6SBrandon Kim {
1585de90619SPatrick Williams throw std::runtime_error(std::format(
1593def3c8eSBrandon Kim "[wraparoundRead] length '{}' was bigger than maxOffset '{}'",
1603def3c8eSBrandon Kim length, maxOffset));
1619836cfa6SBrandon Kim }
1629836cfa6SBrandon Kim
16335d4335eSBrandon Kim // Do a calculation to see if the read will wraparound
16435d4335eSBrandon Kim const size_t queueOffset = getQueueOffset();
1653def3c8eSBrandon Kim const size_t writableSpace = maxOffset - relativeOffset;
16635d4335eSBrandon Kim size_t numWraparoundBytesToRead = 0;
1673def3c8eSBrandon Kim if (length > writableSpace)
16835d4335eSBrandon Kim {
16935d4335eSBrandon Kim // This means we will wrap, count the bytes that are left to read
1703def3c8eSBrandon Kim numWraparoundBytesToRead = length - writableSpace;
17135d4335eSBrandon Kim }
17235d4335eSBrandon Kim const size_t numBytesToReadTillQueueEnd = length - numWraparoundBytesToRead;
17335d4335eSBrandon Kim
17435d4335eSBrandon Kim std::vector<uint8_t> bytesRead = dataInterface->read(
17535d4335eSBrandon Kim queueOffset + relativeOffset, numBytesToReadTillQueueEnd);
17635d4335eSBrandon Kim if (bytesRead.size() != numBytesToReadTillQueueEnd)
17735d4335eSBrandon Kim {
17835d4335eSBrandon Kim throw std::runtime_error(
1795de90619SPatrick Williams std::format("[wraparoundRead] Read '{}' which was not "
18035d4335eSBrandon Kim "the requested length of '{}'",
18135d4335eSBrandon Kim bytesRead.size(), numBytesToReadTillQueueEnd));
18235d4335eSBrandon Kim }
18335d4335eSBrandon Kim size_t updatedReadPtr = relativeOffset + numBytesToReadTillQueueEnd;
1843def3c8eSBrandon Kim if (updatedReadPtr == maxOffset)
1854662b1bdSBrandon Kim {
1864662b1bdSBrandon Kim // If we read all the way up to the end of the queue, we need to
1874662b1bdSBrandon Kim // manually wrap the updateReadPtr around to 0
1884662b1bdSBrandon Kim updatedReadPtr = 0;
1894662b1bdSBrandon Kim }
1909836cfa6SBrandon Kim
1919836cfa6SBrandon Kim // If there are any more bytes to be read beyond the buffer, wrap around and
1929836cfa6SBrandon Kim // read from the beginning of the buffer (offset by the queueOffset)
19335d4335eSBrandon Kim if (numWraparoundBytesToRead > 0)
1949836cfa6SBrandon Kim {
1959836cfa6SBrandon Kim std::vector<uint8_t> wrappedBytesRead =
19635d4335eSBrandon Kim dataInterface->read(queueOffset, numWraparoundBytesToRead);
19735d4335eSBrandon Kim if (numWraparoundBytesToRead != wrappedBytesRead.size())
1989836cfa6SBrandon Kim {
1995de90619SPatrick Williams throw std::runtime_error(std::format(
20035d4335eSBrandon Kim "[wraparoundRead] Buffer wrapped around but read '{}' which "
20135d4335eSBrandon Kim "was not the requested lenght of '{}'",
20235d4335eSBrandon Kim wrappedBytesRead.size(), numWraparoundBytesToRead));
2039836cfa6SBrandon Kim }
2049836cfa6SBrandon Kim bytesRead.insert(bytesRead.end(), wrappedBytesRead.begin(),
2059836cfa6SBrandon Kim wrappedBytesRead.end());
20635d4335eSBrandon Kim updatedReadPtr = numWraparoundBytesToRead;
2079836cfa6SBrandon Kim }
20835d4335eSBrandon Kim updateReadPtr(updatedReadPtr);
2099836cfa6SBrandon Kim
2109836cfa6SBrandon Kim return bytesRead;
2119836cfa6SBrandon Kim }
2129836cfa6SBrandon Kim
readEntryHeader()213613ba537SBrandon Kim struct QueueEntryHeader BufferImpl::readEntryHeader()
2147bac2d69SBrandon Kim {
2157bac2d69SBrandon Kim size_t headerSize = sizeof(struct QueueEntryHeader);
2167bac2d69SBrandon Kim // wraparonudRead will throw if it did not read all the bytes, let it
2177bac2d69SBrandon Kim // propagate up the stack
218613ba537SBrandon Kim std::vector<uint8_t> bytesRead = wraparoundRead(
219613ba537SBrandon Kim boost::endian::little_to_native(cachedBufferHeader.bmcReadPtr),
220613ba537SBrandon Kim headerSize);
2217bac2d69SBrandon Kim
2227bac2d69SBrandon Kim return *reinterpret_cast<struct QueueEntryHeader*>(bytesRead.data());
2237bac2d69SBrandon Kim }
2247bac2d69SBrandon Kim
readEntry()225613ba537SBrandon Kim EntryPair BufferImpl::readEntry()
22640ce08e1SBrandon Kim {
227613ba537SBrandon Kim struct QueueEntryHeader entryHeader = readEntryHeader();
22835d4335eSBrandon Kim size_t entrySize = boost::endian::little_to_native(entryHeader.entrySize);
22940ce08e1SBrandon Kim
23040ce08e1SBrandon Kim // wraparonudRead may throw if entrySize was bigger than the buffer or if it
23126660e9bSBrandon Kim // was not able to read all the bytes, let it propagate up the stack
23235d4335eSBrandon Kim std::vector<uint8_t> entry = wraparoundRead(
233613ba537SBrandon Kim boost::endian::little_to_native(cachedBufferHeader.bmcReadPtr),
234613ba537SBrandon Kim entrySize);
23540ce08e1SBrandon Kim
23640ce08e1SBrandon Kim // Calculate the checksum
23740ce08e1SBrandon Kim uint8_t* entryHeaderPtr = reinterpret_cast<uint8_t*>(&entryHeader);
238f0e4adc9SBrandon Kim uint8_t checksum =
239f0e4adc9SBrandon Kim std::accumulate(entryHeaderPtr,
240f0e4adc9SBrandon Kim entryHeaderPtr + sizeof(struct QueueEntryHeader), 0,
241f0e4adc9SBrandon Kim std::bit_xor<void>()) ^
242f0e4adc9SBrandon Kim std::accumulate(entry.begin(), entry.end(), 0, std::bit_xor<void>());
243f0e4adc9SBrandon Kim
24440ce08e1SBrandon Kim if (checksum != 0)
24540ce08e1SBrandon Kim {
2465de90619SPatrick Williams throw std::runtime_error(std::format(
24740ce08e1SBrandon Kim "[readEntry] Checksum was '{}', expected '0'", checksum));
24840ce08e1SBrandon Kim }
24940ce08e1SBrandon Kim
25040ce08e1SBrandon Kim return {entryHeader, entry};
25140ce08e1SBrandon Kim }
25240ce08e1SBrandon Kim
readErrorLogs()2534662b1bdSBrandon Kim std::vector<EntryPair> BufferImpl::readErrorLogs()
2544662b1bdSBrandon Kim {
2554662b1bdSBrandon Kim // Reading the buffer header will update the cachedBufferHeader
2564662b1bdSBrandon Kim readBufferHeader();
2574662b1bdSBrandon Kim
2583def3c8eSBrandon Kim const size_t maxOffset = getMaxOffset();
2594662b1bdSBrandon Kim size_t currentBiosWritePtr =
2604662b1bdSBrandon Kim boost::endian::little_to_native(cachedBufferHeader.biosWritePtr);
2613def3c8eSBrandon Kim if (currentBiosWritePtr > maxOffset)
2624662b1bdSBrandon Kim {
2635de90619SPatrick Williams throw std::runtime_error(std::format(
2644662b1bdSBrandon Kim "[readErrorLogs] currentBiosWritePtr was '{}' which was bigger "
2653def3c8eSBrandon Kim "than maxOffset '{}'",
2663def3c8eSBrandon Kim currentBiosWritePtr, maxOffset));
2674662b1bdSBrandon Kim }
2684662b1bdSBrandon Kim size_t currentReadPtr =
2694662b1bdSBrandon Kim boost::endian::little_to_native(cachedBufferHeader.bmcReadPtr);
2703def3c8eSBrandon Kim if (currentReadPtr > maxOffset)
2714662b1bdSBrandon Kim {
2725de90619SPatrick Williams throw std::runtime_error(std::format(
2734662b1bdSBrandon Kim "[readErrorLogs] currentReadPtr was '{}' which was bigger "
2743def3c8eSBrandon Kim "than maxOffset '{}'",
2753def3c8eSBrandon Kim currentReadPtr, maxOffset));
2764662b1bdSBrandon Kim }
2774662b1bdSBrandon Kim
2784662b1bdSBrandon Kim size_t bytesToRead;
2794662b1bdSBrandon Kim if (currentBiosWritePtr == currentReadPtr)
2804662b1bdSBrandon Kim {
2814662b1bdSBrandon Kim // No new payload was detected, return an empty vector gracefully
2824662b1bdSBrandon Kim return {};
2834662b1bdSBrandon Kim }
2844662b1bdSBrandon Kim
2854662b1bdSBrandon Kim if (currentBiosWritePtr > currentReadPtr)
2864662b1bdSBrandon Kim {
2874662b1bdSBrandon Kim // Simply subtract in this case
2884662b1bdSBrandon Kim bytesToRead = currentBiosWritePtr - currentReadPtr;
2894662b1bdSBrandon Kim }
2904662b1bdSBrandon Kim else
2914662b1bdSBrandon Kim {
2923def3c8eSBrandon Kim // Calculate the bytes to the "end" (maxOffset - ReadPtr) +
2934662b1bdSBrandon Kim // bytes to read from the "beginning" (0 + WritePtr)
2943def3c8eSBrandon Kim bytesToRead = (maxOffset - currentReadPtr) + currentBiosWritePtr;
2954662b1bdSBrandon Kim }
2964662b1bdSBrandon Kim
2974662b1bdSBrandon Kim size_t byteRead = 0;
2984662b1bdSBrandon Kim std::vector<EntryPair> entryPairs;
2994662b1bdSBrandon Kim while (byteRead < bytesToRead)
3004662b1bdSBrandon Kim {
301613ba537SBrandon Kim EntryPair entryPair = readEntry();
3024662b1bdSBrandon Kim byteRead += sizeof(struct QueueEntryHeader) + entryPair.second.size();
3034662b1bdSBrandon Kim entryPairs.push_back(entryPair);
3044662b1bdSBrandon Kim
3054662b1bdSBrandon Kim // Note: readEntry() will update cachedBufferHeader.bmcReadPtr
3064662b1bdSBrandon Kim currentReadPtr =
3074662b1bdSBrandon Kim boost::endian::little_to_native(cachedBufferHeader.bmcReadPtr);
3084662b1bdSBrandon Kim }
3094662b1bdSBrandon Kim if (currentBiosWritePtr != currentReadPtr)
3104662b1bdSBrandon Kim {
3115de90619SPatrick Williams throw std::runtime_error(std::format(
3124662b1bdSBrandon Kim "[readErrorLogs] biosWritePtr '{}' and bmcReaddPtr '{}' "
3134662b1bdSBrandon Kim "are not identical after reading through all the logs",
3144662b1bdSBrandon Kim currentBiosWritePtr, currentReadPtr));
3154662b1bdSBrandon Kim }
3164662b1bdSBrandon Kim return entryPairs;
3174662b1bdSBrandon Kim }
3184662b1bdSBrandon Kim
getMaxOffset()3193def3c8eSBrandon Kim size_t BufferImpl::getMaxOffset()
3203def3c8eSBrandon Kim {
3213def3c8eSBrandon Kim size_t queueSize =
3223def3c8eSBrandon Kim boost::endian::little_to_native(cachedBufferHeader.queueSize);
3233def3c8eSBrandon Kim size_t ueRegionSize =
3243def3c8eSBrandon Kim boost::endian::little_to_native(cachedBufferHeader.ueRegionSize);
3253def3c8eSBrandon Kim
32682ab8320SBrandon Kim if (queueSize != QUEUE_REGION_SIZE)
32782ab8320SBrandon Kim {
3285de90619SPatrick Williams throw std::runtime_error(std::format(
32982ab8320SBrandon Kim "[{}] runtime queueSize '{}' did not match compile-time queueSize "
33082ab8320SBrandon Kim "'{}'. This indicates that the buffer was corrupted",
33182ab8320SBrandon Kim __FUNCTION__, queueSize, QUEUE_REGION_SIZE));
33282ab8320SBrandon Kim }
33382ab8320SBrandon Kim if (ueRegionSize != UE_REGION_SIZE)
33482ab8320SBrandon Kim {
3355de90619SPatrick Williams throw std::runtime_error(std::format(
33682ab8320SBrandon Kim "[{}] runtime ueRegionSize '{}' did not match compile-time "
33782ab8320SBrandon Kim "ueRegionSize '{}'. This indicates that the buffer was corrupted",
33882ab8320SBrandon Kim __FUNCTION__, ueRegionSize, UE_REGION_SIZE));
33982ab8320SBrandon Kim }
34082ab8320SBrandon Kim
3413def3c8eSBrandon Kim return queueSize - ueRegionSize - sizeof(struct CircularBufferHeader);
3423def3c8eSBrandon Kim }
3433def3c8eSBrandon Kim
getQueueOffset()34482ab8320SBrandon Kim size_t BufferImpl::getQueueOffset()
34582ab8320SBrandon Kim {
34682ab8320SBrandon Kim size_t ueRegionSize =
34782ab8320SBrandon Kim boost::endian::little_to_native(cachedBufferHeader.ueRegionSize);
34882ab8320SBrandon Kim
34982ab8320SBrandon Kim if (ueRegionSize != UE_REGION_SIZE)
35082ab8320SBrandon Kim {
3515de90619SPatrick Williams throw std::runtime_error(std::format(
35282ab8320SBrandon Kim "[{}] runtime ueRegionSize '{}' did not match compile-time "
35382ab8320SBrandon Kim "ueRegionSize '{}'. This indicates that the buffer was corrupted",
35482ab8320SBrandon Kim __FUNCTION__, ueRegionSize, UE_REGION_SIZE));
35582ab8320SBrandon Kim }
35682ab8320SBrandon Kim return sizeof(struct CircularBufferHeader) + ueRegionSize;
35782ab8320SBrandon Kim }
35882ab8320SBrandon Kim
359fcbc3db1SBrandon Kim } // namespace bios_bmc_smm_error_logger
360