xref: /openbmc/bios-bmc-smm-error-logger/include/buffer.hpp (revision d49db6ffa0013a333a33be2b48f0a422d4054c03)
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