Brandon Kim | 1a3dc60 | 2022-06-17 11:34:33 -0700 | [diff] [blame] | 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 | |
Brandon Kim | 554fad0 | 2022-05-15 15:41:05 -0700 | [diff] [blame] | 9 | #include <boost/asio.hpp> |
Brandon Kim | 1a3dc60 | 2022-06-17 11:34:33 -0700 | [diff] [blame] | 10 | #include <boost/endian/conversion.hpp> |
kasunath | a3b64fb | 2022-06-15 18:47:18 -0700 | [diff] [blame] | 11 | #include <sdbusplus/asio/object_server.hpp> |
Brandon Kim | 1a3dc60 | 2022-06-17 11:34:33 -0700 | [diff] [blame] | 12 | #include <stdplus/fd/create.hpp> |
| 13 | #include <stdplus/fd/impl.hpp> |
| 14 | #include <stdplus/fd/managed.hpp> |
Patrick Williams | 5de9061 | 2024-02-13 21:31:53 -0600 | [diff] [blame] | 15 | #include <stdplus/print.hpp> |
Brandon Kim | 554fad0 | 2022-05-15 15:41:05 -0700 | [diff] [blame] | 16 | |
| 17 | #include <chrono> |
Brandon Kim | 1a3dc60 | 2022-06-17 11:34:33 -0700 | [diff] [blame] | 18 | #include <filesystem> |
Patrick Williams | 5de9061 | 2024-02-13 21:31:53 -0600 | [diff] [blame] | 19 | #include <format> |
Brandon Kim | 1a3dc60 | 2022-06-17 11:34:33 -0700 | [diff] [blame] | 20 | #include <fstream> |
Brandon Kim | 554fad0 | 2022-05-15 15:41:05 -0700 | [diff] [blame] | 21 | #include <functional> |
Brandon Kim | 1a3dc60 | 2022-06-17 11:34:33 -0700 | [diff] [blame] | 22 | #include <memory> |
Brandon Kim | 554fad0 | 2022-05-15 15:41:05 -0700 | [diff] [blame] | 23 | |
| 24 | namespace |
| 25 | { |
Brandon Kim | 1a3dc60 | 2022-06-17 11:34:33 -0700 | [diff] [blame] | 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}; |
Brandon Kim | 554fad0 | 2022-05-15 15:41:05 -0700 | [diff] [blame] | 35 | } // namespace |
| 36 | |
Brandon Kim | 1a3dc60 | 2022-06-17 11:34:33 -0700 | [diff] [blame] | 37 | using namespace bios_bmc_smm_error_logger; |
| 38 | |
| 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) |
Brandon Kim | 554fad0 | 2022-05-15 15:41:05 -0700 | [diff] [blame] | 43 | { |
Brandon Kim | 1a3dc60 | 2022-06-17 11:34:33 -0700 | [diff] [blame] | 44 | if (error) |
| 45 | { |
Patrick Williams | 5de9061 | 2024-02-13 21:31:53 -0600 | [diff] [blame] | 46 | stdplus::print(stderr, "Async wait failed {}\n", error.message()); |
Brandon Kim | 1a3dc60 | 2022-06-17 11:34:33 -0700 | [diff] [blame] | 47 | return; |
| 48 | } |
Brandon Kim | aec9986 | 2025-06-08 22:41:40 +0000 | [diff] [blame] | 49 | |
| 50 | try |
Brandon Kim | 1a3dc60 | 2022-06-17 11:34:33 -0700 | [diff] [blame] | 51 | { |
Brandon Kim | aec9986 | 2025-06-08 22:41:40 +0000 | [diff] [blame] | 52 | std::vector<uint8_t> ueLog = |
| 53 | bufferInterface->readUeLogFromReservedRegion(); |
| 54 | if (!ueLog.empty()) |
Brandon Kim | 1a3dc60 | 2022-06-17 11:34:33 -0700 | [diff] [blame] | 55 | { |
Brandon Kim | aec9986 | 2025-06-08 22:41:40 +0000 | [diff] [blame] | 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. |
Brandon Kim | 1a3dc60 | 2022-06-17 11:34:33 -0700 | [diff] [blame] | 74 | auto bufferHeader = bufferInterface->getCachedBufferHeader(); |
Brandon Kim | aec9986 | 2025-06-08 22:41:40 +0000 | [diff] [blame] | 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 | |
Brandon Kim | d49db6f | 2025-06-09 00:03:59 +0000 | [diff] [blame^] | 82 | if (bufferInterface->checkForOverflowAndAcknowledge()) |
| 83 | { |
| 84 | stdplus::print( |
| 85 | stdout, |
| 86 | "[WARN] Buffer overflow had occured and has been acked\n"); |
| 87 | } |
| 88 | |
Brandon Kim | aec9986 | 2025-06-08 22:41:40 +0000 | [diff] [blame] | 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; |
Brandon Kim | 1a3dc60 | 2022-06-17 11:34:33 -0700 | [diff] [blame] | 163 | } |
| 164 | } |
| 165 | |
Brandon Kim | 07d92b1 | 2025-06-06 23:23:53 +0000 | [diff] [blame] | 166 | t->expires_after(readIntervalinMs); |
Brandon Kim | 1a3dc60 | 2022-06-17 11:34:33 -0700 | [diff] [blame] | 167 | t->async_wait( |
| 168 | std::bind_front(readLoop, t, bufferInterface, rdeCommandHandler)); |
Brandon Kim | 554fad0 | 2022-05-15 15:41:05 -0700 | [diff] [blame] | 169 | } |
| 170 | |
| 171 | int main() |
| 172 | { |
| 173 | boost::asio::io_context io; |
Brandon Kim | 1a3dc60 | 2022-06-17 11:34:33 -0700 | [diff] [blame] | 174 | boost::asio::steady_timer t(io, readIntervalinMs); |
Brandon Kim | 554fad0 | 2022-05-15 15:41:05 -0700 | [diff] [blame] | 175 | |
Brandon Kim | 1a3dc60 | 2022-06-17 11:34:33 -0700 | [diff] [blame] | 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)); |
Brandon Kim | 554fad0 | 2022-05-15 15:41:05 -0700 | [diff] [blame] | 187 | |
Brandon Kim | 1a3dc60 | 2022-06-17 11:34:33 -0700 | [diff] [blame] | 188 | // rdeCommandHandler initialization |
kasunath | a3b64fb | 2022-06-15 18:47:18 -0700 | [diff] [blame] | 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"); |
kasunath | a3b64fb | 2022-06-15 18:47:18 -0700 | [diff] [blame] | 192 | |
Brandon Kim | 1a3dc60 | 2022-06-17 11:34:33 -0700 | [diff] [blame] | 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>( |
kasunath | 3d0cd55 | 2022-08-25 20:22:58 -0700 | [diff] [blame] | 197 | conn, "/run/bmcweb", std::move(fileIface)); |
Brandon Kim | 1a3dc60 | 2022-06-17 11:34:33 -0700 | [diff] [blame] | 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))); |
Brandon Kim | 554fad0 | 2022-05-15 15:41:05 -0700 | [diff] [blame] | 206 | io.run(); |
| 207 | |
| 208 | return 0; |
| 209 | } |