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_uint32_t;
18 using boost::endian::little_uint64_t;
19 
20 // EntryPair.first = QueueEntryHeader
21 // EntryPair.second = Error entry in vector of bytes
22 using EntryPair = std::pair<struct QueueEntryHeader, std::vector<uint8_t>>;
23 
24 struct CircularBufferHeader
25 {
26     little_uint32_t bmcInterfaceVersion;        // Offset 0x0
27     little_uint32_t biosInterfaceVersion;       // Offset 0x4
28     std::array<little_uint32_t, 4> magicNumber; // Offset 0x8
29     little_uint16_t queueSize;                  // Offset 0x18
30     little_uint16_t ueRegionSize;               // Offset 0x1a
31     little_uint32_t bmcFlags;                   // Offset 0x1c
32     little_uint16_t bmcReadPtr;                 // Offset 0x20
33     std::array<uint8_t, 6> reserved1;           // Offset 0x22
34     little_uint32_t biosFlags;                  // Offset 0x28
35     little_uint16_t biosWritePtr;               // Offset 0x2c
36     std::array<uint8_t, 2> reserved2;           // Offset 0x2e
37     // UE reserved region:                         Offset 0x30
38     // Error log queue:       Offset 0x30 + UE reserved region
39 
40     bool operator==(const CircularBufferHeader& other) const
41     {
42         /* Skip comparing reserved1 and reserved2 */
43         return std::tie(this->bmcInterfaceVersion, this->biosInterfaceVersion,
44                         this->magicNumber, this->queueSize, this->ueRegionSize,
45                         this->bmcFlags, this->bmcReadPtr, this->biosFlags,
46                         this->biosWritePtr) ==
47                std::tie(other.bmcInterfaceVersion, other.biosInterfaceVersion,
48                         other.magicNumber, other.queueSize, other.ueRegionSize,
49                         other.bmcFlags, other.bmcReadPtr, other.biosFlags,
50                         other.biosWritePtr);
51     }
52 };
53 static_assert(sizeof(CircularBufferHeader) == 0x30,
54               "Size of CircularBufferHeader struct is incorrect.");
55 
56 struct QueueEntryHeader
57 {
58     little_uint16_t sequenceId; // Offset 0x0
59     little_uint16_t entrySize;  // Offset 0x2
60     uint8_t checksum;           // Offset 0x4
61     uint8_t rdeCommandType;     // Offset 0x5
62     // RDE Command                 Offset 0x6
63     bool operator==(const QueueEntryHeader& other) const
64     {
65         return std::tie(this->sequenceId, this->entrySize, this->checksum,
66                         this->rdeCommandType) ==
67                std::tie(other.sequenceId, other.entrySize, other.checksum,
68                         other.rdeCommandType);
69     }
70 };
71 static_assert(sizeof(QueueEntryHeader) == 0x6,
72               "Size of QueueEntryHeader struct is incorrect.");
73 
74 /**
75  * An interface class for the buffer helper APIs
76  */
77 class BufferInterface
78 {
79   public:
80     virtual ~BufferInterface() = default;
81 
82     /**
83      * Zero out the buffer first before populating the header
84      *
85      * @param[in] bmcInterfaceVersion - Used to initialize the header
86      * @param[in] queueSize - Used to initialize the header
87      * @param[in] ueRegionSize - Used to initialize the header
88      * @param[in] magicNumber - Used to initialize the header
89      * @return true if successful
90      */
91     virtual void initialize(uint32_t bmcInterfaceVersion, uint16_t queueSize,
92                             uint16_t ueRegionSize,
93                             const std::array<uint32_t, 4>& magicNumber) = 0;
94 
95     /**
96      * Read the buffer header from shared buffer
97      */
98     virtual void readBufferHeader() = 0;
99 
100     /**
101      * Getter API for the cached buffer header
102      * @return cached CircularBufferHeader
103      */
104     virtual struct CircularBufferHeader getCachedBufferHeader() const = 0;
105 
106     /**
107      * Write to the bufferHeader and update the read pointer
108      * @param[in] newReadPtr - read pointer to update to.
109      *  "readPtr"s (including this one) are offset relative to the "Error Log
110      *  Queue region" = (sizeof(CircularBufferHeader) + UE reserved region)
111      */
112     virtual void updateReadPtr(const uint32_t newReadPtr) = 0;
113 
114     /**
115      * Wrapper for the dataInterface->read, performs wraparound read
116      *
117      * @param[in] offset - offset relative to the beginning of MMIO space
118      * @param[in] length - bytes to read
119      * @param[in] additionalBoundaryCheck - bytes to add to the boundary check
120      * for added restriction
121      * @return the bytes read
122      */
123     virtual std::vector<uint8_t>
124         wraparoundRead(const uint32_t offset, const uint32_t length,
125                        const uint32_t additionalBoundaryCheck) = 0;
126     /**
127      * Read the entry header from shared buffer
128      *
129      * @param[in] offset - offset relative to the beginning of MMIO space
130      * @return the entry header
131      */
132     virtual struct QueueEntryHeader readEntryHeader(size_t offset) = 0;
133 
134     /**
135      * Read the queue entry from the error log queue
136      *
137      * @param[in] offset - offset relative to the beginning of MMIO space
138      * @return entry header and entry pair read from buffer
139      */
140     virtual EntryPair readEntry(size_t offset) = 0;
141 };
142 
143 /**
144  * Buffer implementation class
145  */
146 class BufferImpl : public BufferInterface
147 {
148   public:
149     /** @brief Constructor for BufferImpl
150      *  @param[in] dataInterface     - DataInterface for this object
151      */
152     explicit BufferImpl(std::unique_ptr<DataInterface> dataInterface);
153     void initialize(uint32_t bmcInterfaceVersion, uint16_t queueSize,
154                     uint16_t ueRegionSize,
155                     const std::array<uint32_t, 4>& magicNumber) override;
156     void readBufferHeader() override;
157     struct CircularBufferHeader getCachedBufferHeader() const override;
158     void updateReadPtr(const uint32_t newReadPtr) override;
159     std::vector<uint8_t>
160         wraparoundRead(const uint32_t offset, const uint32_t length,
161                        const uint32_t additionalBoundaryCheck = 0) override;
162     struct QueueEntryHeader readEntryHeader(size_t offset) override;
163     EntryPair readEntry(size_t offset) override;
164 
165   private:
166     /** @brief The Error log queue starts after the UE region, which is where
167      * the read and write pointers are offset from relatively
168      *  @return relative offset for read and write pointers
169      */
170     size_t getQueueOffset();
171 
172     std::unique_ptr<DataInterface> dataInterface;
173     struct CircularBufferHeader cachedBufferHeader = {};
174 };
175 
176 } // namespace bios_bmc_smm_error_logger
177