1 #include "buffer.hpp"
2 
3 #include "pci_handler.hpp"
4 
5 #include <fmt/format.h>
6 
7 #include <boost/endian/arithmetic.hpp>
8 #include <boost/endian/conversion.hpp>
9 
10 #include <algorithm>
11 #include <array>
12 #include <cstddef>
13 #include <cstdint>
14 #include <memory>
15 #include <span>
16 #include <vector>
17 
18 namespace bios_bmc_smm_error_logger
19 {
20 
21 BufferImpl::BufferImpl(std::unique_ptr<DataInterface> dataInterface) :
22     dataInterface(std::move(dataInterface)){};
23 
24 void BufferImpl::initialize(uint32_t bmcInterfaceVersion, uint16_t queueSize,
25                             uint16_t ueRegionSize,
26                             const std::array<uint32_t, 4>& magicNumber)
27 {
28     // Initialize the whole buffer with 0x00
29     const size_t memoryRegionSize = dataInterface->getMemoryRegionSize();
30     const std::vector<uint8_t> emptyVector(memoryRegionSize, 0);
31     size_t byteWritten = dataInterface->write(0, emptyVector);
32     if (byteWritten != memoryRegionSize)
33     {
34         throw std::runtime_error(
35             fmt::format("Buffer initialization only erased '{}'", byteWritten));
36     }
37 
38     // Create an initial buffer header and write to it
39     struct CircularBufferHeader initializationHeader = {};
40     initializationHeader.bmcInterfaceVersion =
41         boost::endian::native_to_little(bmcInterfaceVersion);
42     initializationHeader.queueSize = boost::endian::native_to_little(queueSize);
43     initializationHeader.ueRegionSize =
44         boost::endian::native_to_little(ueRegionSize);
45     std::transform(magicNumber.begin(), magicNumber.end(),
46                    initializationHeader.magicNumber.begin(),
47                    [](uint32_t number) -> little_uint32_t {
48                        return boost::endian::native_to_little(number);
49                    });
50 
51     uint8_t* initializationHeaderPtr =
52         reinterpret_cast<uint8_t*>(&initializationHeader);
53     size_t initializationHeaderSize = sizeof(initializationHeader);
54     byteWritten = dataInterface->write(
55         0, std::span<const uint8_t>(initializationHeaderPtr,
56                                     initializationHeaderPtr +
57                                         initializationHeaderSize));
58     if (byteWritten != initializationHeaderSize)
59     {
60         throw std::runtime_error(fmt::format(
61             "Buffer initialization buffer header write only wrote '{}'",
62             byteWritten));
63     }
64     cachedBufferHeader = initializationHeader;
65 }
66 
67 void BufferImpl::readBufferHeader()
68 {
69     size_t headerSize = sizeof(struct CircularBufferHeader);
70     std::vector<uint8_t> bytesRead =
71         dataInterface->read(/* offset */ 0, headerSize);
72 
73     if (bytesRead.size() != headerSize)
74     {
75         throw std::runtime_error(
76             fmt::format("Buffer header read only read '{}', expected '{}'",
77                         bytesRead.size(), headerSize));
78     }
79 
80     cachedBufferHeader =
81         *reinterpret_cast<struct CircularBufferHeader*>(bytesRead.data());
82 };
83 
84 struct CircularBufferHeader BufferImpl::getCachedBufferHeader() const
85 {
86     return cachedBufferHeader;
87 }
88 
89 void BufferImpl::updateReadPtr(const uint32_t newReadPtr)
90 {
91     constexpr uint8_t bmcReadPtrOffset =
92         offsetof(struct CircularBufferHeader, bmcReadPtr);
93 
94     little_uint16_t truncatedReadPtr =
95         boost::endian::native_to_little(newReadPtr & 0xffff);
96     uint8_t* truncatedReadPtrPtr =
97         reinterpret_cast<uint8_t*>(&truncatedReadPtr);
98 
99     size_t writtenSize = dataInterface->write(
100         bmcReadPtrOffset, std::span<const uint8_t>{
101                               truncatedReadPtrPtr,
102                               truncatedReadPtrPtr + sizeof(little_uint16_t)});
103     if (writtenSize != sizeof(little_uint16_t))
104     {
105         throw std::runtime_error(fmt::format(
106             "[updateReadPtr] Wrote '{}' bytes, instead of expected '{}'",
107             writtenSize, sizeof(little_uint16_t)));
108     }
109     cachedBufferHeader.bmcReadPtr = truncatedReadPtr;
110 }
111 
112 } // namespace bios_bmc_smm_error_logger
113