blob: 29f3e2f288508e1fd73ed3451e09df9842eab89e [file] [log] [blame]
#pragma once
#include "pci_handler.hpp"
#include <boost/endian/arithmetic.hpp>
#include <array>
#include <cstdint>
#include <memory>
#include <tuple>
namespace bios_bmc_smm_error_logger
{
/* Adding endianness */
using boost::endian::little_uint16_t;
using boost::endian::little_uint24_t;
using boost::endian::little_uint32_t;
using boost::endian::little_uint64_t;
// EntryPair.first = QueueEntryHeader
// EntryPair.second = Error entry in vector of bytes
using EntryPair = std::pair<struct QueueEntryHeader, std::vector<uint8_t>>;
enum class BmcFlags : uint32_t
{
ueSwitch = 1,
overflow = 1 << 1,
ready = 1 << 2,
};
struct CircularBufferHeader
{
little_uint32_t bmcInterfaceVersion; // Offset 0x0
little_uint32_t biosInterfaceVersion; // Offset 0x4
std::array<little_uint32_t, 4> magicNumber; // Offset 0x8
little_uint24_t queueSize; // Offset 0x18
little_uint16_t ueRegionSize; // Offset 0x1b
little_uint32_t bmcFlags; // Offset 0x1d
little_uint24_t bmcReadPtr; // Offset 0x21
std::array<uint8_t, 4> reserved1; // Offset 0x24
little_uint32_t biosFlags; // Offset 0x28
little_uint24_t biosWritePtr; // Offset 0x2c
uint8_t reserved2; // Offset 0x2f
// UE reserved region: Offset 0x30
// Error log queue: Offset 0x30 + UE reserved region
bool operator==(const CircularBufferHeader& other) const
{
/* Skip comparing reserved1 and reserved2 */
return std::tie(this->bmcInterfaceVersion, this->biosInterfaceVersion,
this->magicNumber, this->queueSize, this->ueRegionSize,
this->bmcFlags, this->bmcReadPtr, this->biosFlags,
this->biosWritePtr) ==
std::tie(other.bmcInterfaceVersion, other.biosInterfaceVersion,
other.magicNumber, other.queueSize, other.ueRegionSize,
other.bmcFlags, other.bmcReadPtr, other.biosFlags,
other.biosWritePtr);
}
};
static_assert(sizeof(CircularBufferHeader) == 0x30,
"Size of CircularBufferHeader struct is incorrect.");
struct QueueEntryHeader
{
little_uint16_t sequenceId; // Offset 0x0
little_uint16_t entrySize; // Offset 0x2
uint8_t checksum; // Offset 0x4
uint8_t rdeCommandType; // Offset 0x5
// RDE Command Offset 0x6
bool operator==(const QueueEntryHeader& other) const
{
return std::tie(this->sequenceId, this->entrySize, this->checksum,
this->rdeCommandType) ==
std::tie(other.sequenceId, other.entrySize, other.checksum,
other.rdeCommandType);
}
};
static_assert(sizeof(QueueEntryHeader) == 0x6,
"Size of QueueEntryHeader struct is incorrect.");
/**
* An interface class for the buffer helper APIs
*/
class BufferInterface
{
public:
virtual ~BufferInterface() = default;
/**
* Zero out the buffer first before populating the header
*
* @param[in] bmcInterfaceVersion - Used to initialize the header
* @param[in] queueSize - Used to initialize the header
* @param[in] ueRegionSize - Used to initialize the header
* @param[in] magicNumber - Used to initialize the header
* @return true if successful
*/
virtual void initialize(uint32_t bmcInterfaceVersion, uint16_t queueSize,
uint16_t ueRegionSize,
const std::array<uint32_t, 4>& magicNumber) = 0;
/**
* Read the buffer header from shared buffer
*/
virtual void readBufferHeader() = 0;
/**
* Getter API for the cached buffer header
* @return cached CircularBufferHeader
*/
virtual struct CircularBufferHeader getCachedBufferHeader() const = 0;
/**
* Write to the bufferHeader and update the read pointer
* @param[in] newReadPtr - read pointer to update to
*/
virtual void updateReadPtr(const uint32_t newReadPtr) = 0;
/**
* Write to the bufferHeader and update the BMC flags
* @param[in] newBmcFlags - new flag to update to
*/
virtual void updateBmcFlags(const uint32_t newBmcFlags) = 0;
/**
* Wrapper for the dataInterface->read, performs wraparound read
*
* @param[in] relativeOffset - offset relative the "Error Log
* Queue region" = (sizeof(CircularBufferHeader) + UE reserved region)
* @param[in] length - bytes to read
* @return the bytes read
*/
virtual std::vector<uint8_t> wraparoundRead(const uint32_t relativeOffset,
const uint32_t length) = 0;
/**
* Read the entry header from shared buffer from the read pointer
*
* @return the entry header
*/
virtual struct QueueEntryHeader readEntryHeader() = 0;
/**
* Read the queue entry from the error log queue from the read pointer
*
* * @return entry header and entry pair read from buffer
*/
virtual EntryPair readEntry() = 0;
/**
* Read the buffer - this API should be used instead of individual functions
* above
*
* @return vector of EntryPair which consists of entry header and entry
*/
virtual std::vector<EntryPair> readErrorLogs() = 0;
/**
* Get max offset for the queue
*
* * @return Queue size - UE region size - Queue header size
*/
virtual size_t getMaxOffset() = 0;
};
/**
* Buffer implementation class
*/
class BufferImpl : public BufferInterface
{
public:
/** @brief Constructor for BufferImpl
* @param[in] dataInterface - DataInterface for this object
*/
explicit BufferImpl(std::unique_ptr<DataInterface> dataInterface);
void initialize(uint32_t bmcInterfaceVersion, uint16_t queueSize,
uint16_t ueRegionSize,
const std::array<uint32_t, 4>& magicNumber) override;
void readBufferHeader() override;
struct CircularBufferHeader getCachedBufferHeader() const override;
void updateReadPtr(const uint32_t newReadPtr) override;
void updateBmcFlags(const uint32_t newBmcFlag) override;
std::vector<uint8_t> wraparoundRead(const uint32_t relativeOffset,
const uint32_t length) override;
struct QueueEntryHeader readEntryHeader() override;
EntryPair readEntry() override;
std::vector<EntryPair> readErrorLogs() override;
size_t getMaxOffset() override;
private:
/** @brief The Error log queue starts after the UE region, which is where
* the read and write pointers are offset from relatively
* @return relative offset for read and write pointers
*/
size_t getQueueOffset();
/** @brief Calculate the checksum by XOR each bytes in the span
* @param[in] entry - Span to calculate the checksum on
* @return calculated checksum
*/
uint8_t calculateChecksum(std::span<uint8_t> entry);
std::unique_ptr<DataInterface> dataInterface;
struct CircularBufferHeader cachedBufferHeader = {};
};
} // namespace bios_bmc_smm_error_logger