| #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 |