1 #pragma once 2 3 #include "additional_data.hpp" 4 #include "data_interface.hpp" 5 #include "private_header.hpp" 6 #include "registry.hpp" 7 #include "src.hpp" 8 #include "user_data.hpp" 9 #include "user_data_formats.hpp" 10 #include "user_header.hpp" 11 12 #include <memory> 13 #include <vector> 14 15 namespace openpower 16 { 17 namespace pels 18 { 19 20 /** 21 * @brief Contains information about an FFDC file. 22 */ 23 struct PelFFDCfile 24 { 25 UserDataFormat format; 26 uint8_t subType; 27 uint8_t version; 28 int fd; 29 }; 30 31 using PelFFDC = std::vector<PelFFDCfile>; 32 33 constexpr uint8_t jsonCalloutSubtype = 0xCA; 34 35 /** @class PEL 36 * 37 * @brief This class represents a specific event log format referred to as a 38 * Platform Event Log. 39 * 40 * Every field in a PEL are in structures call sections, of which there are 41 * several types. Some sections are required, and some are optional. In some 42 * cases there may be more than one instance of a section type. 43 * 44 * The only two required sections for every type of PEL are the Private Header 45 * section and User Header section, which must be in the first and second 46 * positions, respectively. 47 * 48 * Every section starts with an 8 byte section header, which has the section 49 * size and type, among other things. 50 * 51 * This class represents all sections with objects. 52 * 53 * The class can be constructed: 54 * - From a full formed flattened PEL. 55 * - From scratch based on an OpenBMC event and its corresponding PEL message 56 * registry entry. 57 * 58 * The data() method allows one to retrieve the PEL as a vector<uint8_t>. This 59 * is the format in which it is stored and transmitted. 60 */ 61 class PEL 62 { 63 public: 64 PEL() = delete; 65 ~PEL() = default; 66 PEL(const PEL&) = delete; 67 PEL& operator=(const PEL&) = delete; 68 PEL(PEL&&) = delete; 69 PEL& operator=(PEL&&) = delete; 70 71 /** 72 * @brief Constructor 73 * 74 * Build a PEL from raw data. 75 * 76 * Note: Neither this nor the following constructor can take a const vector& 77 * because the Stream class that is used to read from the vector cannot take 78 * a const. The alternative is to make a copy of the data, but as PELs can 79 * be up to 16KB that is undesireable. 80 * 81 * @param[in] data - The PEL data 82 */ 83 explicit PEL(std::vector<uint8_t>& data); 84 85 /** 86 * @brief Constructor 87 * 88 * Build a PEL from the raw data. 89 * 90 * @param[in] data - the PEL data 91 * @param[in] obmcLogID - the corresponding OpenBMC event log ID 92 */ 93 PEL(std::vector<uint8_t>& data, uint32_t obmcLogID); 94 95 /** 96 * @brief Constructor 97 * 98 * Creates a PEL from an OpenBMC event log and its message 99 * registry entry. 100 * 101 * @param[in] entry - The message registry entry for this error 102 * @param[in] obmcLogID - ID of corresponding OpenBMC event log 103 * @param[in] timestamp - Timestamp from the event log 104 * @param[in] severity - Severity from the event log 105 * @param[in] additionalData - The AdditionalData contents 106 * @param[in] ffdcFiles - FFCD files that go into UserData sections 107 * @param[in] dataIface - The data interface object 108 */ 109 PEL(const openpower::pels::message::Entry& entry, uint32_t obmcLogID, 110 uint64_t timestamp, phosphor::logging::Entry::Level severity, 111 const AdditionalData& additionalData, const PelFFDC& ffdcFiles, 112 const DataInterfaceBase& dataIface); 113 114 /** 115 * @brief Convenience function to return the log ID field from the 116 * Private Header section. 117 * 118 * @return uint32_t - the ID 119 */ 120 uint32_t id() const 121 { 122 return _ph->id(); 123 } 124 125 /** 126 * @brief Convenience function to return the PLID field from the 127 * Private Header section. 128 * 129 * @return uint32_t - the PLID 130 */ 131 uint32_t plid() const 132 { 133 return _ph->plid(); 134 } 135 136 /** 137 * @brief Convenience function to return the OpenBMC event log ID field 138 * from the Private Header section. 139 * 140 * @return uint32_t - the OpenBMC event log ID 141 */ 142 uint32_t obmcLogID() const 143 { 144 return _ph->obmcLogID(); 145 } 146 147 /** 148 * @brief Convenience function to return the commit time field from 149 * the Private Header section. 150 * 151 * @return BCDTime - the timestamp 152 */ 153 BCDTime commitTime() const 154 { 155 return _ph->commitTimestamp(); 156 } 157 158 /** 159 * @brief Convenience function to return the create time field from 160 * the Private Header section. 161 * 162 * @return BCDTime - the timestamp 163 */ 164 BCDTime createTime() const 165 { 166 return _ph->createTimestamp(); 167 } 168 169 /** 170 * @brief Gives access to the Private Header section class 171 * 172 * @return const PrivateHeader& - the private header 173 */ 174 const PrivateHeader& privateHeader() const 175 { 176 return *_ph; 177 } 178 179 /** 180 * @brief Gives access to the User Header section class 181 * 182 * @return const UserHeader& - the user header 183 */ 184 const UserHeader& userHeader() const 185 { 186 return *_uh; 187 } 188 189 /** 190 * @brief Gives access to the primary SRC's section class 191 * 192 * This is technically an optional section, so the return 193 * value is an std::optional<SRC*>. 194 * 195 * @return std::optional<SRC*> - the SRC section object 196 */ 197 std::optional<SRC*> primarySRC() const; 198 199 /** 200 * @brief Returns the optional sections, which is everything but 201 * the Private and User Headers. 202 * 203 * @return const std::vector<std::unique_ptr<Section>>& 204 */ 205 const std::vector<std::unique_ptr<Section>>& optionalSections() const 206 { 207 return _optionalSections; 208 } 209 210 /** 211 * @brief Returns the PEL data. 212 * 213 * @return std::vector<uint8_t> - the raw PEL data 214 */ 215 std::vector<uint8_t> data() const; 216 217 /** 218 * @brief Returns the size of the PEL 219 * 220 * @return size_t The PEL size in bytes 221 */ 222 size_t size() const; 223 224 /** 225 * @brief Says if the PEL is valid (the sections are all valid) 226 * 227 * @return bool - if the PEL is valid 228 */ 229 bool valid() const; 230 231 /** 232 * @brief Sets the commit timestamp to the current time 233 */ 234 void setCommitTime(); 235 236 /** 237 * @brief Sets the error log ID field to a unique ID. 238 */ 239 void assignID(); 240 241 /** 242 * @brief Output a PEL in JSON. 243 * @param[in] registry - Registry object reference 244 * @param[in] plugins - Vector of strings of plugins found in filesystem 245 */ 246 void toJSON(message::Registry& registry, 247 const std::vector<std::string>& plugins) const; 248 249 /** 250 * @brief Sets the host transmission state in the User Header 251 * 252 * @param[in] state - The state value 253 */ 254 void setHostTransmissionState(TransmissionState state) 255 { 256 _uh->setHostTransmissionState(static_cast<uint8_t>(state)); 257 } 258 259 /** 260 * @brief Returns the host transmission state 261 * 262 * @return HostTransmissionState - The state 263 */ 264 TransmissionState hostTransmissionState() const 265 { 266 return static_cast<TransmissionState>(_uh->hostTransmissionState()); 267 } 268 269 /** 270 * @brief Sets the HMC transmission state in the User Header 271 * 272 * @param[in] state - The state value 273 */ 274 void setHMCTransmissionState(TransmissionState state) 275 { 276 _uh->setHMCTransmissionState(static_cast<uint8_t>(state)); 277 } 278 279 /** 280 * @brief Returns the HMC transmission state 281 * 282 * @return HMCTransmissionState - The state 283 */ 284 TransmissionState hmcTransmissionState() const 285 { 286 return static_cast<TransmissionState>(_uh->hmcTransmissionState()); 287 } 288 289 /** 290 * @brief Returns true if a hardware callout is present in the primary SRC 291 * 292 * @return true if hardware callout present, false otherwise 293 */ 294 bool isHwCalloutPresent() const; 295 296 /** 297 * @brief Updates the system info data into HB extended user 298 * data section to this PEL object 299 * 300 * @param[in] dataIface - The data interface object 301 */ 302 void updateSysInfoInExtendedUserDataSection( 303 const DataInterfaceBase& dataIface); 304 305 private: 306 /** 307 * @brief Builds the section objects from a PEL data buffer 308 * 309 * Note: The data parameter cannot be const for the same reasons 310 * as listed in the constructor. 311 * 312 * @param[in] data - The PEL data 313 * @param[in] obmcLogID - The OpenBMC event log ID to use for that 314 * field in the Private Header. 315 */ 316 void populateFromRawData(std::vector<uint8_t>& data, uint32_t obmcLogID); 317 318 /** 319 * @brief Flattens the PEL objects into the buffer 320 * 321 * @param[out] pelBuffer - What the data will be written to 322 */ 323 void flatten(std::vector<uint8_t>& pelBuffer) const; 324 325 /** 326 * @brief Check that the PEL fields that need to be in agreement 327 * with each other are, and fix them up if necessary. 328 */ 329 void checkRulesAndFix(); 330 331 /** 332 * @brief Returns a map of the section IDs that appear more than once 333 * in the PEL. The data value for each entry will be set to 0. 334 * 335 * @return std::map<uint16_t, size_t> 336 */ 337 std::map<uint16_t, size_t> getPluralSections() const; 338 339 /** 340 * @brief Adds the UserData section to this PEL object, 341 * shrinking it if necessary 342 * 343 * @param[in] userData - The section to add 344 * 345 * @return bool - If the section was added or not. 346 */ 347 bool addUserDataSection(std::unique_ptr<UserData> userData); 348 349 /** 350 * @brief helper function for printing PELs. 351 * @param[in] Section& - section object reference 352 * @param[in] std::string - PEL string 353 * @param[in|out] pluralSections - Map used to track sections counts for 354 * when there is more than 1. 355 * @param[in] registry - Registry object reference 356 * @param[in] plugins - Vector of strings of plugins found in filesystem 357 * @param[in] creatorID - Creator Subsystem ID (only for UserData section) 358 */ 359 void printSectionInJSON(const Section& section, std::string& buf, 360 std::map<uint16_t, size_t>& pluralSections, 361 message::Registry& registry, 362 const std::vector<std::string>& plugins, 363 uint8_t creatorID = 0) const; 364 365 /** 366 * @brief Returns any callout JSON found in the FFDC files. 367 * 368 * Looks for an FFDC file that is JSON format and has the 369 * sub-type value set to 0xCA and returns its data as a JSON object. 370 * 371 * @param[in] ffdcFiles - FFCD files that go into UserData sections 372 * 373 * @return json - The callout JSON, or an empty object if not found 374 */ 375 nlohmann::json getCalloutJSON(const PelFFDC& ffdcFiles); 376 377 /** 378 * @brief Update terminate bit in primary SRC section to this PEL object is 379 * severity set to 0x51 = critical error, system termination 380 */ 381 void updateTerminateBitInSRCSection(); 382 383 /** 384 * @brief The PEL Private Header section 385 */ 386 std::unique_ptr<PrivateHeader> _ph; 387 388 /** 389 * @brief The PEL User Header section 390 */ 391 std::unique_ptr<UserHeader> _uh; 392 393 /** 394 * @brief Holds all sections by the PH and UH. 395 */ 396 std::vector<std::unique_ptr<Section>> _optionalSections; 397 398 /** 399 * @brief The maximum size a PEL can be in bytes. 400 */ 401 static constexpr size_t _maxPELSize = 16384; 402 }; 403 404 namespace util 405 { 406 407 /** 408 * @brief Creates a UserData section object that contains JSON. 409 * 410 * @param[in] json - The JSON contents 411 * 412 * @return std::unique_ptr<UserData> - The UserData object 413 */ 414 std::unique_ptr<UserData> makeJSONUserDataSection(const nlohmann::json& json); 415 416 /** 417 * @brief Create a UserData section containing the AdditionalData 418 * contents as a JSON string. 419 * 420 * @param[in] ad - The AdditionalData contents 421 * 422 * @return std::unique_ptr<UserData> - The section 423 */ 424 std::unique_ptr<UserData> makeADUserDataSection(const AdditionalData& ad); 425 426 /** 427 * @brief Create a UserData section containing various useful pieces 428 * of system information as a JSON string. 429 * 430 * @param[in] ad - The AdditionalData contents 431 * @param[in] dataIface - The data interface object 432 * @param[in] addUptime - Whether to add the uptime attribute the default is 433 * true 434 * 435 * @return std::unique_ptr<UserData> - The section 436 */ 437 std::unique_ptr<UserData> 438 makeSysInfoUserDataSection(const AdditionalData& ad, 439 const DataInterfaceBase& dataIface, 440 bool addUptime = true); 441 442 /** 443 * @brief Reads data from an opened file descriptor. 444 * 445 * @param[in] fd - The FD to read from 446 * 447 * @return std::vector<uint8_t> - The data read 448 */ 449 std::vector<uint8_t> readFD(int fd); 450 451 /** 452 * @brief Create a UserData section that contains the data in the file 453 * pointed to by the file descriptor passed in. 454 * 455 * @param[in] componentID - The component ID of the PEL creator 456 * @param[in] file - The FFDC file information 457 */ 458 std::unique_ptr<UserData> makeFFDCuserDataSection(uint16_t componentID, 459 const PelFFDCfile& file); 460 } // namespace util 461 462 } // namespace pels 463 } // namespace openpower 464