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