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 <cstdint>
13 #include <memory>
14 #include <span>
15 #include <vector>
16 
17 namespace bios_bmc_smm_error_logger
18 {
19 
20 BufferImpl::BufferImpl(std::unique_ptr<DataInterface> dataInterface) :
21     dataInterface(std::move(dataInterface)){};
22 
23 void BufferImpl::initialize(uint32_t bmcInterfaceVersion, uint16_t queueSize,
24                             uint16_t ueRegionSize,
25                             const std::array<uint32_t, 4>& magicNumber)
26 {
27     // Initialize the whole buffer with 0x00
28     const size_t memoryRegionSize = dataInterface->getMemoryRegionSize();
29     const std::vector<uint8_t> emptyVector(memoryRegionSize, 0);
30     size_t byteWritten = dataInterface->write(0, emptyVector);
31     if (byteWritten != memoryRegionSize)
32     {
33         throw std::runtime_error(
34             fmt::format("Buffer initialization only erased '{}'", byteWritten));
35     }
36 
37     // Create an initial buffer header and write to it
38     struct CircularBufferHeader initializationHeader = {};
39     initializationHeader.bmcInterfaceVersion =
40         boost::endian::native_to_little(bmcInterfaceVersion);
41     initializationHeader.queueSize = boost::endian::native_to_little(queueSize);
42     initializationHeader.ueRegionSize =
43         boost::endian::native_to_little(ueRegionSize);
44     std::transform(magicNumber.begin(), magicNumber.end(),
45                    initializationHeader.magicNumber.begin(),
46                    [](uint32_t number) -> little_uint32_t {
47                        return boost::endian::native_to_little(number);
48                    });
49 
50     uint8_t* initializationHeaderPtr =
51         reinterpret_cast<uint8_t*>(&initializationHeader);
52     size_t initializationHeaderSize = sizeof(initializationHeader);
53     byteWritten = dataInterface->write(
54         0, std::span<const uint8_t>(initializationHeaderPtr,
55                                     initializationHeaderPtr +
56                                         initializationHeaderSize));
57     if (byteWritten != initializationHeaderSize)
58     {
59         throw std::runtime_error(fmt::format(
60             "Buffer initialization buffer header write only wrote '{}'",
61             byteWritten));
62     }
63 }
64 
65 void BufferImpl::readBufferHeader()
66 {
67     size_t headerSize = sizeof(struct CircularBufferHeader);
68     std::vector<uint8_t> bytesRead =
69         dataInterface->read(/* offset */ 0, headerSize);
70 
71     if (bytesRead.size() != headerSize)
72     {
73         throw std::runtime_error(
74             fmt::format("Buffer header read only read '{}', expected '{}'",
75                         bytesRead.size(), headerSize));
76     }
77 
78     cachedBufferHeader =
79         *reinterpret_cast<CircularBufferHeader*>(bytesRead.data());
80 };
81 
82 struct CircularBufferHeader BufferImpl::getCachedBufferHeader() const
83 {
84     return cachedBufferHeader;
85 }
86 
87 } // namespace bios_bmc_smm_error_logger
88