1 #pragma once 2 3 #include "pci_handler.hpp" 4 5 #include <boost/endian/arithmetic.hpp> 6 7 #include <array> 8 #include <cstdint> 9 #include <memory> 10 #include <tuple> 11 12 namespace bios_bmc_smm_error_logger 13 { 14 15 /* Adding endianness */ 16 using boost::endian::little_uint16_t; 17 using boost::endian::little_uint24_t; 18 using boost::endian::little_uint32_t; 19 using boost::endian::little_uint64_t; 20 21 // EntryPair.first = QueueEntryHeader 22 // EntryPair.second = Error entry in vector of bytes 23 using EntryPair = std::pair<struct QueueEntryHeader, std::vector<uint8_t>>; 24 25 enum class BufferFlags : uint32_t 26 { 27 ueSwitch = 1 << 0, 28 overflow = 1 << 1, 29 }; 30 31 enum class BmcFlags : uint32_t 32 { 33 ready = 1 << 2, 34 }; 35 36 struct CircularBufferHeader 37 { 38 little_uint32_t bmcInterfaceVersion; // Offset 0x0 39 little_uint32_t biosInterfaceVersion; // Offset 0x4 40 std::array<little_uint32_t, 4> magicNumber; // Offset 0x8 41 little_uint24_t queueSize; // Offset 0x18 42 little_uint16_t ueRegionSize; // Offset 0x1b 43 little_uint32_t bmcFlags; // Offset 0x1d 44 little_uint24_t bmcReadPtr; // Offset 0x21 45 std::array<uint8_t, 4> reserved1; // Offset 0x24 46 little_uint32_t biosFlags; // Offset 0x28 47 little_uint24_t biosWritePtr; // Offset 0x2c 48 uint8_t reserved2; // Offset 0x2f 49 // UE reserved region: Offset 0x30 50 // Error log queue: Offset 0x30 + UE reserved region 51 operator ==bios_bmc_smm_error_logger::CircularBufferHeader52 bool operator==(const CircularBufferHeader& other) const 53 { 54 /* Skip comparing reserved1 and reserved2 */ 55 return std::tie(this->bmcInterfaceVersion, this->biosInterfaceVersion, 56 this->magicNumber, this->queueSize, this->ueRegionSize, 57 this->bmcFlags, this->bmcReadPtr, this->biosFlags, 58 this->biosWritePtr) == 59 std::tie(other.bmcInterfaceVersion, other.biosInterfaceVersion, 60 other.magicNumber, other.queueSize, other.ueRegionSize, 61 other.bmcFlags, other.bmcReadPtr, other.biosFlags, 62 other.biosWritePtr); 63 } 64 }; 65 static_assert(sizeof(CircularBufferHeader) == 0x30, 66 "Size of CircularBufferHeader struct is incorrect."); 67 68 struct QueueEntryHeader 69 { 70 little_uint16_t sequenceId; // Offset 0x0 71 little_uint16_t entrySize; // Offset 0x2 72 uint8_t checksum; // Offset 0x4 73 uint8_t rdeCommandType; // Offset 0x5 74 // RDE Command Offset 0x6 operator ==bios_bmc_smm_error_logger::QueueEntryHeader75 bool operator==(const QueueEntryHeader& other) const 76 { 77 return std::tie(this->sequenceId, this->entrySize, this->checksum, 78 this->rdeCommandType) == 79 std::tie(other.sequenceId, other.entrySize, other.checksum, 80 other.rdeCommandType); 81 } 82 }; 83 static_assert(sizeof(QueueEntryHeader) == 0x6, 84 "Size of QueueEntryHeader struct is incorrect."); 85 86 /** 87 * An interface class for the buffer helper APIs 88 */ 89 class BufferInterface 90 { 91 public: 92 virtual ~BufferInterface() = default; 93 94 /** 95 * Zero out the buffer first before populating the header 96 * 97 * @param[in] bmcInterfaceVersion - Used to initialize the header 98 * @param[in] queueSize - Used to initialize the header 99 * @param[in] ueRegionSize - Used to initialize the header 100 * @param[in] magicNumber - Used to initialize the header 101 * @return true if successful 102 */ 103 virtual void initialize(uint32_t bmcInterfaceVersion, uint16_t queueSize, 104 uint16_t ueRegionSize, 105 const std::array<uint32_t, 4>& magicNumber) = 0; 106 /** 107 * Check for unread Uncorrecatble Error (UE) logs and read them if present 108 */ 109 virtual std::vector<uint8_t> readUeLogFromReservedRegion() = 0; 110 111 /** 112 * Check for overflow and ackknolwedge if not acked yet 113 */ 114 virtual bool checkForOverflowAndAcknowledge() = 0; 115 116 /** 117 * Read the buffer header from shared buffer 118 */ 119 virtual void readBufferHeader() = 0; 120 121 /** 122 * Getter API for the cached buffer header 123 * @return cached CircularBufferHeader 124 */ 125 virtual struct CircularBufferHeader getCachedBufferHeader() const = 0; 126 127 /** 128 * Write to the bufferHeader and update the read pointer 129 * @param[in] newReadPtr - read pointer to update to 130 */ 131 virtual void updateReadPtr(const uint32_t newReadPtr) = 0; 132 133 /** 134 * Write to the bufferHeader and update the BMC flags 135 * @param[in] newBmcFlags - new flag to update to 136 */ 137 virtual void updateBmcFlags(const uint32_t newBmcFlags) = 0; 138 139 /** 140 * Wrapper for the dataInterface->read, performs wraparound read 141 * 142 * @param[in] relativeOffset - offset relative the "Error Log 143 * Queue region" = (sizeof(CircularBufferHeader) + UE reserved region) 144 * @param[in] length - bytes to read 145 * @return the bytes read 146 */ 147 virtual std::vector<uint8_t> wraparoundRead(const uint32_t relativeOffset, 148 const uint32_t length) = 0; 149 /** 150 * Read the entry header from shared buffer from the read pointer 151 * 152 * @return the entry header 153 */ 154 virtual struct QueueEntryHeader readEntryHeader() = 0; 155 156 /** 157 * Read the queue entry from the error log queue from the read pointer 158 * 159 * * @return entry header and entry pair read from buffer 160 */ 161 virtual EntryPair readEntry() = 0; 162 163 /** 164 * Read the buffer - this API should be used instead of individual functions 165 * above 166 * 167 * @return vector of EntryPair which consists of entry header and entry 168 */ 169 virtual std::vector<EntryPair> readErrorLogs() = 0; 170 171 /** 172 * Get max offset for the queue 173 * 174 * * @return Queue size - UE region size - Queue header size 175 */ 176 virtual size_t getMaxOffset() = 0; 177 178 /** @brief The Error log queue starts after the UE region, which is where 179 * the read and write pointers are offset from relatively 180 * @return relative offset for read and write pointers 181 */ 182 virtual size_t getQueueOffset() = 0; 183 }; 184 185 /** 186 * Buffer implementation class 187 */ 188 class BufferImpl : public BufferInterface 189 { 190 public: 191 /** @brief Constructor for BufferImpl 192 * @param[in] dataInterface - DataInterface for this object 193 */ 194 explicit BufferImpl(std::unique_ptr<DataInterface> dataInterface); 195 void initialize(uint32_t bmcInterfaceVersion, uint16_t queueSize, 196 uint16_t ueRegionSize, 197 const std::array<uint32_t, 4>& magicNumber) override; 198 std::vector<uint8_t> readUeLogFromReservedRegion() override; 199 bool checkForOverflowAndAcknowledge() override; 200 void readBufferHeader() override; 201 struct CircularBufferHeader getCachedBufferHeader() const override; 202 void updateReadPtr(const uint32_t newReadPtr) override; 203 void updateBmcFlags(const uint32_t newBmcFlag) override; 204 std::vector<uint8_t> wraparoundRead(const uint32_t relativeOffset, 205 const uint32_t length) override; 206 struct QueueEntryHeader readEntryHeader() override; 207 EntryPair readEntry() override; 208 std::vector<EntryPair> readErrorLogs() override; 209 size_t getMaxOffset() override; 210 size_t getQueueOffset() override; 211 212 private: 213 /** @brief Calculate the checksum by XOR each bytes in the span 214 * @param[in] entry - Span to calculate the checksum on 215 * @return calculated checksum 216 */ 217 uint8_t calculateChecksum(std::span<uint8_t> entry); 218 219 std::unique_ptr<DataInterface> dataInterface; 220 struct CircularBufferHeader cachedBufferHeader = {}; 221 }; 222 223 } // namespace bios_bmc_smm_error_logger 224