xref: /openbmc/bios-bmc-smm-error-logger/src/main.cpp (revision d49db6ffa0013a333a33be2b48f0a422d4054c03)
1 #include "config.h"
2 
3 #include "buffer.hpp"
4 #include "pci_handler.hpp"
5 #include "rde/external_storer_file.hpp"
6 #include "rde/external_storer_interface.hpp"
7 #include "rde/rde_handler.hpp"
8 
9 #include <boost/asio.hpp>
10 #include <boost/endian/conversion.hpp>
11 #include <sdbusplus/asio/object_server.hpp>
12 #include <stdplus/fd/create.hpp>
13 #include <stdplus/fd/impl.hpp>
14 #include <stdplus/fd/managed.hpp>
15 #include <stdplus/print.hpp>
16 
17 #include <chrono>
18 #include <filesystem>
19 #include <format>
20 #include <fstream>
21 #include <functional>
22 #include <memory>
23 
24 namespace
25 {
26 constexpr std::chrono::milliseconds readIntervalinMs(READ_INTERVAL_MS);
27 constexpr std::size_t memoryRegionSize = MEMORY_REGION_SIZE;
28 constexpr std::size_t memoryRegionOffset = MEMORY_REGION_OFFSET;
29 constexpr uint32_t bmcInterfaceVersion = BMC_INTERFACE_VERSION;
30 constexpr uint16_t queueSize = QUEUE_REGION_SIZE;
31 constexpr uint16_t ueRegionSize = UE_REGION_SIZE;
32 static constexpr std::array<uint32_t, 4> magicNumber = {
33     MAGIC_NUMBER_BYTE1, MAGIC_NUMBER_BYTE2, MAGIC_NUMBER_BYTE3,
34     MAGIC_NUMBER_BYTE4};
35 } // namespace
36 
37 using namespace bios_bmc_smm_error_logger;
38 
readLoop(boost::asio::steady_timer * t,const std::shared_ptr<BufferInterface> & bufferInterface,const std::shared_ptr<rde::RdeCommandHandler> & rdeCommandHandler,const boost::system::error_code & error)39 void readLoop(boost::asio::steady_timer* t,
40               const std::shared_ptr<BufferInterface>& bufferInterface,
41               const std::shared_ptr<rde::RdeCommandHandler>& rdeCommandHandler,
42               const boost::system::error_code& error)
43 {
44     if (error)
45     {
46         stdplus::print(stderr, "Async wait failed {}\n", error.message());
47         return;
48     }
49 
50     try
51     {
52         std::vector<uint8_t> ueLog =
53             bufferInterface->readUeLogFromReservedRegion();
54         if (!ueLog.empty())
55         {
56             stdplus::print(
57                 stdout,
58                 "UE log found in reserved region, attempting to process\n");
59 
60             // UE log is BEJ encoded data, requiring RdeOperationInitRequest
61             rde::RdeDecodeStatus ueDecodeStatus =
62                 rdeCommandHandler->decodeRdeCommand(
63                     ueLog, rde::RdeCommandType::RdeOperationInitRequest);
64 
65             if (ueDecodeStatus != rde::RdeDecodeStatus::RdeOk &&
66                 ueDecodeStatus != rde::RdeDecodeStatus::RdeStopFlagReceived)
67             {
68                 throw std::runtime_error(std::format(
69                     "Corruption detected processing UE log from reserved region. RDE decode status: {}",
70                     static_cast<int>(ueDecodeStatus)));
71             }
72             stdplus::print(stdout, "UE log processed successfully.\n");
73             // Successfully processed. Toggle BMC's view of ueSwitch flag.
74             auto bufferHeader = bufferInterface->getCachedBufferHeader();
75             uint32_t bmcSideFlags =
76                 boost::endian::little_to_native(bufferHeader.bmcFlags);
77             uint32_t newBmcFlags =
78                 bmcSideFlags ^ static_cast<uint32_t>(BufferFlags::ueSwitch);
79             bufferInterface->updateBmcFlags(newBmcFlags);
80         }
81 
82         if (bufferInterface->checkForOverflowAndAcknowledge())
83         {
84             stdplus::print(
85                 stdout,
86                 "[WARN] Buffer overflow had occured and has been acked\n");
87         }
88 
89         std::vector<EntryPair> entryPairs = bufferInterface->readErrorLogs();
90         for (const auto& [entryHeader, entry] : entryPairs)
91         {
92             rde::RdeDecodeStatus rdeDecodeStatus =
93                 rdeCommandHandler->decodeRdeCommand(
94                     entry, static_cast<rde::RdeCommandType>(
95                                entryHeader.rdeCommandType));
96             if (rdeDecodeStatus == rde::RdeDecodeStatus::RdeStopFlagReceived)
97             {
98                 auto bufferHeader = bufferInterface->getCachedBufferHeader();
99                 auto newbmcFlags =
100                     boost::endian::little_to_native(bufferHeader.bmcFlags) |
101                     static_cast<uint32_t>(BmcFlags::ready);
102                 bufferInterface->updateBmcFlags(newbmcFlags);
103             }
104         }
105     }
106     catch (const std::exception& e)
107     {
108         stdplus::print(
109             stderr,
110             "Error during log processing (std::exception): {}. Attempting to reinitialize buffer.\n",
111             e.what());
112         try
113         {
114             bufferInterface->initialize(bmcInterfaceVersion, queueSize,
115                                         ueRegionSize, magicNumber);
116             stdplus::print(
117                 stdout,
118                 "Buffer reinitialized successfully after std::exception.\n");
119         }
120         catch (const std::exception& reinit_e)
121         {
122             stdplus::print(
123                 stderr,
124                 "CRITICAL: Failed to reinitialize buffer (std::exception): {}. Terminating read loop.\n",
125                 reinit_e.what());
126             return;
127         }
128         catch (...)
129         {
130             stdplus::print(
131                 stderr,
132                 "CRITICAL: Failed to reinitialize buffer (unknown exception). Terminating read loop.\n");
133             return;
134         }
135     }
136     catch (...)
137     {
138         stdplus::print(
139             stderr,
140             "Unknown error during log processing. Attempting to reinitialize buffer.\n");
141         try
142         {
143             bufferInterface->initialize(bmcInterfaceVersion, queueSize,
144                                         ueRegionSize, magicNumber);
145             stdplus::print(
146                 stdout,
147                 "Buffer reinitialized successfully after unknown error.\n");
148         }
149         catch (const std::exception& reinit_e)
150         {
151             stdplus::print(
152                 stderr,
153                 "CRITICAL: Failed to reinitialize buffer (std::exception): {}. Terminating read loop.\n",
154                 reinit_e.what());
155             return;
156         }
157         catch (...)
158         {
159             stdplus::print(
160                 stderr,
161                 "CRITICAL: Failed to reinitialize buffer (unknown exception). Terminating read loop.\n");
162             return;
163         }
164     }
165 
166     t->expires_after(readIntervalinMs);
167     t->async_wait(
168         std::bind_front(readLoop, t, bufferInterface, rdeCommandHandler));
169 }
170 
main()171 int main()
172 {
173     boost::asio::io_context io;
174     boost::asio::steady_timer t(io, readIntervalinMs);
175 
176     // bufferHandler initialization
177     std::unique_ptr<stdplus::ManagedFd> managedFd =
178         std::make_unique<stdplus::ManagedFd>(stdplus::fd::open(
179             "/dev/mem",
180             stdplus::fd::OpenFlags(stdplus::fd::OpenAccess::ReadWrite)
181                 .set(stdplus::fd::OpenFlag::Sync)));
182     std::unique_ptr<DataInterface> pciDataHandler =
183         std::make_unique<PciDataHandler>(memoryRegionOffset, memoryRegionSize,
184                                          std::move(managedFd));
185     std::shared_ptr<BufferInterface> bufferHandler =
186         std::make_shared<BufferImpl>(std::move(pciDataHandler));
187 
188     // rdeCommandHandler initialization
189     std::shared_ptr<sdbusplus::asio::connection> conn =
190         std::make_shared<sdbusplus::asio::connection>(io);
191     conn->request_name("xyz.openbmc_project.bios_bmc_smm_error_logger");
192 
193     std::unique_ptr<rde::FileHandlerInterface> fileIface =
194         std::make_unique<rde::ExternalStorerFileWriter>();
195     std::unique_ptr<rde::ExternalStorerInterface> exFileIface =
196         std::make_unique<rde::ExternalStorerFileInterface>(
197             conn, "/run/bmcweb", std::move(fileIface));
198     std::shared_ptr<rde::RdeCommandHandler> rdeCommandHandler =
199         std::make_unique<rde::RdeCommandHandler>(std::move(exFileIface));
200 
201     bufferHandler->initialize(bmcInterfaceVersion, queueSize, ueRegionSize,
202                               magicNumber);
203 
204     t.async_wait(std::bind_front(readLoop, &t, std::move(bufferHandler),
205                                  std::move(rdeCommandHandler)));
206     io.run();
207 
208     return 0;
209 }
210