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 /**
53  * An interface class for the buffer helper APIs
54  */
55 class BufferInterface
56 {
57   public:
58     virtual ~BufferInterface() = default;
59 
60     /**
61      * Zero out the buffer first before populating the header
62      *
63      * @param[in] bmcInterfaceVersion - Used to initialize the header
64      * @param[in] queueSize - Used to initialize the header
65      * @param[in] ueRegionSize - Used to initialize the header
66      * @param[in] magicNumber - Used to initialize the header
67      * @return true if successful
68      */
69     virtual void initialize(uint32_t bmcInterfaceVersion, uint16_t queueSize,
70                             uint16_t ueRegionSize,
71                             const std::array<uint32_t, 4>& magicNumber) = 0;
72 
73     /**
74      * Read the buffer header from shared buffer
75      */
76     virtual void readBufferHeader() = 0;
77 
78     /**
79      * Getter API for the cached buffer header
80      * @return cached CircularBufferHeader
81      */
82     virtual struct CircularBufferHeader getCachedBufferHeader() const = 0;
83 
84     /**
85      * Write to the bufferHeader and update the read pointer
86      * @param[in] newReadPtr - read pointer to update to
87      */
88     virtual void updateReadPtr(const uint32_t newReadPtr) = 0;
89 
90     /**
91      * Wrapper for the dataInterface->read, performs wraparound read
92      *
93      * @param[in] offset - offset to read from
94      * @param[in] length - bytes to read
95      * @param[in] additionalBoundaryCheck - bytes to add to the boundary check
96      * for added restriction
97      * @return the bytes read
98      */
99     virtual std::vector<uint8_t>
100         wraparoundRead(const uint32_t offset, const uint32_t length,
101                        const uint32_t additionalBoundaryCheck) = 0;
102 };
103 
104 /**
105  * Buffer implementation class
106  */
107 class BufferImpl : public BufferInterface
108 {
109   public:
110     /** @brief Constructor for BufferImpl
111      *  @param[in] dataInterface     - DataInterface for this object
112      */
113     explicit BufferImpl(std::unique_ptr<DataInterface> dataInterface);
114     void initialize(uint32_t bmcInterfaceVersion, uint16_t queueSize,
115                     uint16_t ueRegionSize,
116                     const std::array<uint32_t, 4>& magicNumber) override;
117     void readBufferHeader() override;
118     struct CircularBufferHeader getCachedBufferHeader() const override;
119     void updateReadPtr(const uint32_t newReadPtr) override;
120     std::vector<uint8_t>
121         wraparoundRead(const uint32_t offset, const uint32_t length,
122                        const uint32_t additionalBoundaryCheck = 0) override;
123 
124   private:
125     /** @brief The Error log queue starts after the UE region, which is where
126      * the read and write pointers are offset from relatively
127      *  @return relative offset for read and write pointers
128      */
129     size_t getQueueOffset();
130 
131     std::unique_ptr<DataInterface> dataInterface;
132     struct CircularBufferHeader cachedBufferHeader = {};
133 };
134 
135 } // namespace bios_bmc_smm_error_logger
136