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