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