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