1 #include "create_pel.hpp" 2 3 #include "dump_utils.hpp" 4 #include "sbe_consts.hpp" 5 6 #include <fcntl.h> 7 #include <libekb.H> 8 #include <unistd.h> 9 10 #include <phosphor-logging/elog.hpp> 11 #include <phosphor-logging/lg2.hpp> 12 #include <xyz/openbmc_project/Logging/Create/server.hpp> 13 #include <xyz/openbmc_project/Logging/Entry/server.hpp> 14 15 #include <cerrno> 16 #include <cstdio> 17 #include <cstdlib> 18 #include <cstring> 19 #include <format> 20 #include <map> 21 #include <stdexcept> 22 #include <string> 23 #include <tuple> 24 #include <vector> 25 26 namespace openpower::dump::pel 27 { 28 29 using namespace phosphor::logging; 30 using namespace openpower::dump::SBE; 31 constexpr auto loggingObjectPath = "/xyz/openbmc_project/logging"; 32 constexpr auto loggingInterface = "xyz.openbmc_project.Logging.Create"; 33 constexpr auto opLoggingInterface = "org.open_power.Logging.PEL"; 34 constexpr auto entryInterface = "xyz.openbmc_project.Logging.Entry"; 35 constexpr auto opEntryInterface = "org.open_power.Logging.PEL.Entry"; 36 37 uint32_t createSbeErrorPEL(const std::string& event, const sbeError_t& sbeError, 38 const FFDCData& ffdcData, const Severity severity, 39 const std::optional<PELFFDCInfo>& pelFFDCInfoOpt) 40 { 41 uint32_t plid = 0; 42 std::unordered_map<std::string, std::string> additionalData = { 43 {"_PID", std::to_string(getpid())}, {"SBE_ERR_MSG", sbeError.what()}}; 44 auto bus = sdbusplus::bus::new_default(); 45 46 additionalData.emplace("_PID", std::to_string(getpid())); 47 additionalData.emplace("SBE_ERR_MSG", sbeError.what()); 48 49 for (auto& data : ffdcData) 50 { 51 additionalData.emplace(data); 52 } 53 54 PELFFDCInfo pelFFDCInfo; 55 if (pelFFDCInfoOpt) 56 { 57 pelFFDCInfo = *pelFFDCInfoOpt; 58 } 59 60 // Negative fd value indicates error case or invalid file 61 // No need of special processing , just log error with additional ffdc. 62 else if (sbeError.getFd() > 0) 63 { 64 // Refer phosphor-logging/extensions/openpower-pels/README.md section 65 // "Self Boot Engine(SBE) First Failure Data Capture(FFDC) Support" 66 // for details of related to createPEL with SBE FFDC information 67 // using CreateWithFFDCFiles api. 68 pelFFDCInfo.emplace_back(std::make_tuple( 69 sdbusplus::xyz::openbmc_project::Logging::server::Create:: 70 FFDCFormat::Custom, 71 FFDC_FORMAT_SUBTYPE, FFDC_FORMAT_VERSION, sbeError.getFd())); 72 } 73 try 74 { 75 auto service = 76 util::getService(bus, opLoggingInterface, loggingObjectPath); 77 auto method = 78 bus.new_method_call(service.c_str(), loggingObjectPath, 79 opLoggingInterface, "CreatePELWithFFDCFiles"); 80 auto level = 81 sdbusplus::xyz::openbmc_project::Logging::server::convertForMessage( 82 severity); 83 method.append(event, level, additionalData, pelFFDCInfo); 84 auto response = bus.call(method); 85 86 // reply will be tuple containing bmc log id, platform log id 87 std::tuple<uint32_t, uint32_t> reply = {0, 0}; 88 89 // parse dbus response into reply 90 response.read(reply); 91 plid = std::get<0>(reply); // dbus entry id is tuple "first" 92 } 93 catch (const sdbusplus::exception_t& e) 94 { 95 lg2::error( 96 "D-Bus call exception OBJPATH={OBJPATH}, INTERFACE={INTERFACE}, " 97 "EXCEPTION={ERROR}", 98 "OBJPATH", loggingObjectPath, "INTERFACE", loggingInterface, 99 "ERROR", e); 100 101 throw; 102 } 103 catch (const std::exception& e) 104 { 105 throw; 106 } 107 108 return plid; 109 } 110 111 openpower::dump::pel::Severity convertSeverityToEnum(uint8_t severity) 112 { 113 switch (severity) 114 { 115 case openpower::phal::FAPI2_ERRL_SEV_RECOVERED: 116 return openpower::dump::pel::Severity::Informational; 117 case openpower::phal::FAPI2_ERRL_SEV_PREDICTIVE: 118 return openpower::dump::pel::Severity::Warning; 119 case openpower::phal::FAPI2_ERRL_SEV_UNRECOVERABLE: 120 return openpower::dump::pel::Severity::Error; 121 default: 122 return openpower::dump::pel::Severity::Error; 123 } 124 } 125 126 std::vector<uint32_t> processFFDCPackets( 127 const openpower::phal::sbeError_t& sbeError, const std::string& event, 128 openpower::dump::pel::FFDCData& pelAdditionalData) 129 { 130 const auto& ffdcFileList = sbeError.getFfdcFileList(); 131 std::vector<uint32_t> logIdList; 132 for (const auto& [slid, ffdcTuple] : ffdcFileList) 133 { 134 uint8_t severity; 135 int fd; 136 std::filesystem::path path; 137 std::tie(severity, fd, path) = ffdcTuple; 138 139 Severity logSeverity = convertSeverityToEnum(severity); 140 141 if (logSeverity != openpower::dump::pel::Severity::Informational) 142 { 143 lg2::info( 144 "Changing severity from {SEV_ORIG} to informational in the " 145 "dumping path", 146 "SEV_ORIG", logSeverity); 147 logSeverity = openpower::dump::pel::Severity::Informational; 148 } 149 150 PELFFDCInfo pelFFDCInfo; 151 pelFFDCInfo.emplace_back( 152 std::make_tuple(sdbusplus::xyz::openbmc_project::Logging::server:: 153 Create::FFDCFormat::Custom, 154 FFDC_FORMAT_SUBTYPE, FFDC_FORMAT_VERSION, fd)); 155 156 auto logId = openpower::dump::pel::createSbeErrorPEL( 157 event, sbeError, pelAdditionalData, logSeverity); 158 lg2::info("Logged PEL {PELID} for SLID {SLID}", "PELID", logId, "SLID", 159 slid); 160 logIdList.push_back(logId); 161 } 162 return logIdList; 163 } 164 165 std::tuple<uint32_t, std::string> getLogInfo(uint32_t logId) 166 { 167 uint32_t pelId; 168 std::string src; 169 try 170 { 171 auto bus = sdbusplus::bus::new_default(); 172 const auto loggingEntryObjectPath = 173 std::string(loggingObjectPath) + "/entry/" + std::to_string(logId); 174 auto service = 175 util::getService(bus, entryInterface, loggingEntryObjectPath); 176 auto method = 177 bus.new_method_call(service.c_str(), loggingEntryObjectPath.c_str(), 178 "org.freedesktop.DBus.Properties", "Get"); 179 method.append(opEntryInterface); 180 method.append("PlatformLogID"); 181 auto response = bus.call(method); 182 std::variant<uint32_t, std::string> v; 183 response.read(v); 184 pelId = std::get<uint32_t>(v); 185 method = 186 bus.new_method_call(service.c_str(), loggingEntryObjectPath.c_str(), 187 "org.freedesktop.DBus.Properties", "Get"); 188 method.append(entryInterface); 189 method.append("EventId"); 190 response = bus.call(method); 191 response.read(v); 192 std::istringstream iss(std::get<std::string>(v)); 193 iss >> src; 194 } 195 catch (const sdbusplus::exception::exception& e) 196 { 197 lg2::error("D-Bus call exception " 198 "EXCEPTION={ERROR}", 199 "ERROR", e); 200 throw; 201 } 202 catch (const std::exception& e) 203 { 204 throw; 205 } 206 207 return std::tuple<uint32_t, std::string>(pelId, src); 208 } 209 210 FFDCFile::FFDCFile(const json& pHALCalloutData) : 211 calloutData(pHALCalloutData.dump()), 212 calloutFile("/tmp/phalPELCalloutsJson.XXXXXX"), fileFD(-1) 213 { 214 prepareFFDCFile(); 215 } 216 217 FFDCFile::~FFDCFile() 218 { 219 removeCalloutFile(); 220 } 221 222 int FFDCFile::getFileFD() const 223 { 224 return fileFD; 225 } 226 227 void FFDCFile::prepareFFDCFile() 228 { 229 createCalloutFile(); 230 writeCalloutData(); 231 setCalloutFileSeekPos(); 232 } 233 234 void FFDCFile::createCalloutFile() 235 { 236 fileFD = mkostemp(const_cast<char*>(calloutFile.c_str()), O_RDWR); 237 238 if (fileFD == -1) 239 { 240 lg2::error("Failed to create phalPELCallouts file({FILE}), " 241 "errorno({ERRNO}) and errormsg({ERRORMSG})", 242 "FILE", calloutFile, "ERRNO", errno, "ERRORMSG", 243 strerror(errno)); 244 throw std::runtime_error("Failed to create phalPELCallouts file"); 245 } 246 } 247 248 void FFDCFile::writeCalloutData() 249 { 250 ssize_t rc = write(fileFD, calloutData.c_str(), calloutData.size()); 251 252 if (rc == -1) 253 { 254 lg2::error("Failed to write phaPELCallout info in file({FILE}), " 255 "errorno({ERRNO}), errormsg({ERRORMSG})", 256 "FILE", calloutFile, "ERRNO", errno, "ERRORMSG", 257 strerror(errno)); 258 throw std::runtime_error("Failed to write phalPELCallouts info"); 259 } 260 else if (rc != static_cast<ssize_t>(calloutData.size())) 261 { 262 lg2::warning("Could not write all phal callout info in file({FILE}), " 263 "written byte({WRITTEN}), total byte({TOTAL})", 264 "FILE", calloutFile, "WRITTEN", rc, "TOTAL", 265 calloutData.size()); 266 } 267 } 268 269 void FFDCFile::setCalloutFileSeekPos() 270 { 271 int rc = lseek(fileFD, 0, SEEK_SET); 272 273 if (rc == -1) 274 { 275 lg2::error("Failed to set SEEK_SET for phalPELCallouts in " 276 "file({FILE}), errorno({ERRNO}), errormsg({ERRORMSG})", 277 "FILE", calloutFile, "ERRNO", errno, "ERRORMSG", 278 strerror(errno)); 279 280 throw std::runtime_error( 281 "Failed to set SEEK_SET for phalPELCallouts file"); 282 } 283 } 284 285 void FFDCFile::removeCalloutFile() 286 { 287 close(fileFD); 288 std::remove(calloutFile.c_str()); 289 } 290 291 } // namespace openpower::dump::pel 292