1 #pragma once 2 3 #include "additional_data.hpp" 4 #include "ascii_string.hpp" 5 #include "callouts.hpp" 6 #include "data_interface.hpp" 7 #include "pel_types.hpp" 8 #include "registry.hpp" 9 #include "section.hpp" 10 #include "stream.hpp" 11 12 namespace openpower 13 { 14 namespace pels 15 { 16 17 constexpr uint8_t srcSectionVersion = 0x01; 18 constexpr uint8_t srcSectionSubtype = 0x01; 19 constexpr size_t numSRCHexDataWords = 8; 20 constexpr uint8_t srcVersion = 0x02; 21 constexpr uint8_t bmcSRCFormat = 0x55; 22 constexpr uint8_t primaryBMCPosition = 0x10; 23 constexpr size_t baseSRCSize = 72; 24 25 enum class DetailLevel 26 { 27 message = 0x01, 28 json = 0x02 29 }; 30 /** 31 * @class SRC 32 * 33 * SRC stands for System Reference Code. 34 * 35 * This class represents the SRC sections in the PEL, of which there are 2: 36 * primary SRC and secondary SRC. These are the same structurally, the 37 * difference is that the primary SRC must be the 3rd section in the PEL if 38 * present and there is only one of them, and the secondary SRC sections are 39 * optional and there can be more than one (by definition, for there to be a 40 * secondary SRC, a primary SRC must also exist). 41 * 42 * This section consists of: 43 * - An 8B header (Has the version, flags, hexdata word count, and size fields) 44 * - 8 4B words of hex data 45 * - An ASCII character string 46 * - An optional subsection for Callouts 47 */ 48 class SRC : public Section 49 { 50 public: 51 enum HeaderFlags 52 { 53 additionalSections = 0x01, 54 powerFaultEvent = 0x02, 55 hypDumpInit = 0x04, 56 i5OSServiceEventBit = 0x10, 57 virtualProgressSRC = 0x80 58 }; 59 60 /** 61 * @brief Enums for the error status bits in hex word 5 62 * of BMC SRCs. 63 */ 64 enum class ErrorStatusFlags 65 { 66 deconfigured = 0x02000000, 67 guarded = 0x01000000 68 }; 69 70 SRC() = delete; 71 ~SRC() = default; 72 SRC(const SRC&) = delete; 73 SRC& operator=(const SRC&) = delete; 74 SRC(SRC&&) = delete; 75 SRC& operator=(SRC&&) = delete; 76 77 /** 78 * @brief Constructor 79 * 80 * Fills in this class's data fields from the stream. 81 * 82 * @param[in] pel - the PEL data stream 83 */ 84 explicit SRC(Stream& pel); 85 86 /** 87 * @brief Constructor 88 * 89 * Creates the section with data from the PEL message registry entry for 90 * this error, along with the AdditionalData property contents from the 91 * corresponding event log. 92 * 93 * @param[in] regEntry - The message registry entry for this event log 94 * @param[in] additionalData - The AdditionalData properties in this event 95 * log 96 * @param[in] dataIface - The DataInterface object 97 */ 98 SRC(const message::Entry& regEntry, const AdditionalData& additionalData, 99 const DataInterfaceBase& dataIface) : 100 SRC(regEntry, additionalData, nlohmann::json{}, dataIface) 101 { 102 } 103 104 /** 105 * @brief Constructor 106 * 107 * Creates the section with data from the PEL message registry entry for 108 * this error, along with the AdditionalData property contents from the 109 * corresponding event log, and a JSON array of callouts to add. 110 * 111 * @param[in] regEntry - The message registry entry for this event log 112 * @param[in] additionalData - The AdditionalData properties in this event 113 * log 114 * @param[in] jsonCallouts - The array of JSON callouts, or an empty object. 115 * @param[in] dataIface - The DataInterface object 116 */ 117 SRC(const message::Entry& regEntry, const AdditionalData& additionalData, 118 const nlohmann::json& jsonCallouts, const DataInterfaceBase& dataIface); 119 120 /** 121 * @brief Flatten the section into the stream 122 * 123 * @param[in] stream - The stream to write to 124 */ 125 void flatten(Stream& stream) const override; 126 127 /** 128 * @brief Returns the SRC version, which is a different field 129 * than the version byte in the section header. 130 * 131 * @return uint8_t 132 */ 133 uint8_t version() const 134 { 135 return _version; 136 } 137 138 /** 139 * @brief Returns the flags byte 140 * 141 * @return uint8_t 142 */ 143 uint8_t flags() const 144 { 145 return _flags; 146 } 147 148 /** 149 * @brief Returns the hex data word count. 150 * 151 * Even though there always 8 words, this returns 9 due to previous 152 * SRC version formats. 153 * 154 * @return uint8_t 155 */ 156 uint8_t hexWordCount() const 157 { 158 return _wordCount; 159 } 160 161 /** 162 * @brief Returns the size of the SRC section, not including the header. 163 * 164 * @return uint16_t 165 */ 166 uint16_t size() const 167 { 168 return _size; 169 } 170 171 /** 172 * @brief Returns the 8 hex data words. 173 * 174 * @return const std::array<uint32_t, numSRCHexDataWords>& 175 */ 176 const std::array<uint32_t, numSRCHexDataWords>& hexwordData() const 177 { 178 return _hexData; 179 } 180 181 /** 182 * @brief Returns the ASCII string 183 * 184 * @return std::string 185 */ 186 std::string asciiString() const 187 { 188 return _asciiString->get(); 189 } 190 191 /** 192 * @brief Returns the callouts subsection 193 * 194 * If no callouts, this unique_ptr will be empty 195 * 196 * @return const std::unique_ptr<src::Callouts>& 197 */ 198 const std::unique_ptr<src::Callouts>& callouts() const 199 { 200 return _callouts; 201 } 202 203 /** 204 * @brief Returns the size of this section when flattened into a PEL 205 * 206 * @return size_t - the size of the section 207 */ 208 size_t flattenedSize() const 209 { 210 return _header.size; 211 } 212 213 /** 214 * @brief Says if this SRC has additional subsections in it 215 * 216 * Note: The callouts section is the only possible subsection. 217 * 218 * @return bool 219 */ 220 inline bool hasAdditionalSections() const 221 { 222 return _flags & additionalSections; 223 } 224 225 /** 226 * @brief Indicates if this event log is for a power fault. 227 * 228 * This comes from a field in the message registry for BMC 229 * generated PELs. 230 * 231 * @return bool 232 */ 233 inline bool isPowerFaultEvent() const 234 { 235 return _flags & powerFaultEvent; 236 } 237 238 /** 239 * @brief Get the _hexData[] index to use based on the corresponding 240 * SRC word number. 241 * 242 * Converts the specification nomenclature to this data structure. 243 * See the _hexData documentation below for more information. 244 * 245 * @param[in] wordNum - The SRC word number, as defined by the spec. 246 * 247 * @return size_t The corresponding index into _hexData. 248 */ 249 inline size_t getWordIndexFromWordNum(size_t wordNum) const 250 { 251 assert(wordNum >= 2 && wordNum <= 9); 252 return wordNum - 2; 253 } 254 255 /** 256 * @brief Get section in JSON. 257 * @param[in] registry - Registry object reference 258 * @param[in] plugins - Vector of strings of plugins found in filesystem 259 * @param[in] creatorID - Creator Subsystem ID from Private Header 260 * @return std::optional<std::string> - SRC section's JSON 261 */ 262 std::optional<std::string> getJSON(message::Registry& registry, 263 const std::vector<std::string>& plugins, 264 uint8_t creatorID) const override; 265 266 /** 267 * @brief Get error details based on refcode and hexwords 268 * @param[in] registry - Registry object 269 * @param[in] type - detail level enum value : single message or full json 270 * @param[in] toCache - boolean to cache registry in memory, default=false 271 * @return std::optional<std::string> - Error details 272 */ 273 std::optional<std::string> getErrorDetails(message::Registry& registry, 274 DetailLevel type, 275 bool toCache = false) const; 276 277 /** 278 * @brief Says if this SRC was created by the BMC (i.e. this code). 279 * 280 * @return bool - If created by the BMC or not 281 */ 282 bool isBMCSRC() const; 283 284 private: 285 /** 286 * @brief Fills in the user defined hex words from the 287 * AdditionalData fields. 288 * 289 * When creating this section from a message registry entry, 290 * that entry has a field that says which AdditionalData property 291 * fields to use to fill in the user defined hex data words 6-9 292 * (which correspond to hexData words 4-7). 293 * 294 * For example, given that AdditionalData is a map of string keys 295 * to string values, find the AdditionalData value for AdditionalData 296 * key X, convert it to a uint32_t, and save it in user data word Y. 297 * 298 * @param[in] regEntry - The message registry entry for the error 299 * @param[in] additionalData - The AdditionalData map 300 */ 301 void setUserDefinedHexWords(const message::Entry& regEntry, 302 const AdditionalData& additionalData); 303 /** 304 * @brief Fills in the object from the stream data 305 * 306 * @param[in] stream - The stream to read from 307 */ 308 void unflatten(Stream& stream); 309 310 /** 311 * @brief Says if the word number is in the range of user defined words. 312 * 313 * This is only used for BMC generated SRCs, where words 6 - 9 are the 314 * user defined ones, meaning that setUserDefinedHexWords() will be 315 * used to fill them in based on the contents of the OpenBMC event log. 316 * 317 * @param[in] wordNum - The SRC word number, as defined by the spec. 318 * 319 * @return bool - If this word number can be filled in by the creator. 320 */ 321 inline bool isUserDefinedWord(size_t wordNum) const 322 { 323 return (wordNum >= 6) && (wordNum <= 9); 324 } 325 326 /** 327 * @brief Sets the SRC format byte in the hex word data. 328 */ 329 inline void setBMCFormat() 330 { 331 _hexData[0] |= bmcSRCFormat; 332 } 333 334 /** 335 * @brief Sets the hex word field that specifies which BMC 336 * (primary vs backup) created the error. 337 * 338 * Can be hardcoded until there are systems with redundant BMCs. 339 */ 340 inline void setBMCPosition() 341 { 342 _hexData[1] |= primaryBMCPosition; 343 } 344 345 /** 346 * @brief Sets the motherboard CCIN hex word field 347 * 348 * @param[in] dataIface - The DataInterface object 349 */ 350 void setMotherboardCCIN(const DataInterfaceBase& dataIface); 351 352 /** 353 * @brief Sets an error status bit in the SRC. 354 * 355 * @param[in] flag - The flag to set 356 */ 357 void setErrorStatusFlag(ErrorStatusFlags flag) 358 { 359 _hexData[3] |= static_cast<uint32_t>(flag); 360 } 361 362 /** 363 * @brief Validates the section contents 364 * 365 * Updates _valid (in Section) with the results. 366 */ 367 void validate() override; 368 369 /** 370 * @brief Get error description from message registry 371 * @param[in] regEntry - The message registry entry for the error 372 * @return std::optional<std::string> - Error message 373 */ 374 std::optional<std::string> 375 getErrorMessage(const message::Entry& regEntry) const; 376 377 /** 378 * @brief Get Callout info in JSON 379 * @return std::optional<std::string> - Callout details 380 */ 381 std::optional<std::string> getCallouts() const; 382 383 /** 384 * @brief Checks the AdditionalData property and the message registry 385 * JSON and adds any necessary callouts. 386 * 387 * The callout sources are the AdditionalData event log property 388 * and the message registry JSON. 389 * 390 * @param[in] regEntry - The message registry entry for the error 391 * @param[in] additionalData - The AdditionalData values 392 * @param[in] jsonCallouts - The array of JSON callouts, or an empty object 393 * @param[in] dataIface - The DataInterface object 394 */ 395 void addCallouts(const message::Entry& regEntry, 396 const AdditionalData& additionalData, 397 const nlohmann::json& jsonCallouts, 398 const DataInterfaceBase& dataIface); 399 400 /** 401 * @brief Adds a FRU callout based on an inventory path 402 * 403 * @param[in] inventoryPath - The inventory item to call out 404 * @param[in] priority - An optional priority (uses high if nullopt) 405 * @param[in] locationCode - The expanded location code (or look it up) 406 * @param[in] dataIface - The DataInterface object 407 * @param[in] mrus - The MRUs to add to the callout 408 */ 409 void 410 addInventoryCallout(const std::string& inventoryPath, 411 const std::optional<CalloutPriority>& priority, 412 const std::optional<std::string>& locationCode, 413 const DataInterfaceBase& dataIface, 414 const std::vector<src::MRU::MRUCallout>& mrus = {}); 415 416 /** 417 * @brief Returns the callouts to use from the registry entry. 418 * 419 * @param[in] regEntry - The message registry entry for the error 420 * @param[in] additionalData - The AdditionalData property 421 * @param[in] dataIface - The DataInterface object 422 */ 423 std::vector<message::RegistryCallout> 424 getRegistryCallouts(const message::Entry& regEntry, 425 const AdditionalData& additionalData, 426 const DataInterfaceBase& dataIface); 427 428 /** 429 * @brief Adds the FRU callouts from the list of registry callouts 430 * passed in to the SRC. 431 * 432 * The last parameter is used only in a special case when the first 433 * callout is a symbolic FRU with a trusted location code. See the 434 * addRegistryCallout documentation. 435 * 436 * @param[in] callouts - The message registry callouts to add 437 * @param[in] dataIface - The DataInterface object 438 * @param[in] trustedSymbolicFRUInvPath - The optional inventory path used 439 * in the symbolic FRU case. 440 */ 441 void addRegistryCallouts( 442 const std::vector<message::RegistryCallout>& callouts, 443 const DataInterfaceBase& dataIface, 444 std::optional<std::string> trustedSymbolicFRUInvPath); 445 446 /** 447 * @brief Adds a single FRU callout from the message registry. 448 * 449 * If the last parameter is filled in, and the registry callout is a 450 * symbolic FRU callout with a trusted location code, and it has the 451 * 'useInventoryLocCode' member set to true, then the location code of 452 * that inventory item will be what is used for that trusted location code. 453 * 454 * @param[in] callout - The registry callout structure 455 * @param[in] dataIface - The DataInterface object 456 * @param[in] trustedSymbolicFRUInvPath - The optional inventory path used 457 * in the symbolic FRU case. 458 */ 459 void addRegistryCallout( 460 const message::RegistryCallout& callout, 461 const DataInterfaceBase& dataIface, 462 const std::optional<std::string>& trustedSymbolicFRUInvPath); 463 464 /** 465 * @brief Creates the Callouts object _callouts 466 * so that callouts can be added to it. 467 */ 468 void createCalloutsObject() 469 { 470 if (!_callouts) 471 { 472 _callouts = std::make_unique<src::Callouts>(); 473 _flags |= additionalSections; 474 } 475 } 476 477 /** 478 * @brief Adds any FRU callouts based on a device path in the 479 * AdditionalData parameter. 480 * 481 * @param[in] additionalData - The AdditionalData values 482 * @param[in] dataIface - The DataInterface object 483 */ 484 void addDevicePathCallouts(const AdditionalData& additionalData, 485 const DataInterfaceBase& dataIface); 486 487 /** 488 * @brief Adds any FRU callouts specified in the incoming JSON. 489 * 490 * @param[in] jsonCallouts - The JSON array of callouts 491 * @param[in] dataIface - The DataInterface object 492 */ 493 void addJSONCallouts(const nlohmann::json& jsonCallouts, 494 const DataInterfaceBase& dataIface); 495 496 /** 497 * @brief Adds a single callout based on the JSON 498 * 499 * @param[in] jsonCallouts - A single callout entry 500 * @param[in] dataIface - The DataInterface object 501 */ 502 void addJSONCallout(const nlohmann::json& jsonCallout, 503 const DataInterfaceBase& dataIface); 504 505 /** 506 * @brief Extracts a CalloutPriority value from the json 507 * using the 'Priority' key. 508 * 509 * @param[in] json - A JSON object that contains the priority key 510 * 511 * @return CalloutPriority - The priority value 512 */ 513 CalloutPriority getPriorityFromJSON(const nlohmann::json& json); 514 515 /** 516 * @brief Exracts MRU values and their priorities from the 517 * input JSON array. 518 * 519 * @param[in] mruJSON - The JSON array 520 */ 521 std::vector<src::MRU::MRUCallout> 522 getMRUsFromJSON(const nlohmann::json& mruJSON); 523 524 /** 525 * @brief Sets the dump status 526 * 527 * @param[in] dataIface - The DataInterface object 528 */ 529 void setDumpStatus(const DataInterfaceBase& dataIface); 530 531 /** 532 * @brief The SRC version field 533 */ 534 uint8_t _version; 535 536 /** 537 * @brief The SRC flags field 538 */ 539 uint8_t _flags; 540 541 /** 542 * @brief A byte of reserved data after the flags field 543 */ 544 uint8_t _reserved1B; 545 546 /** 547 * @brief The hex data word count. 548 * 549 * To be compatible with previous versions of SRCs, this is 550 * number of hex words (8) + 1 = 9. 551 */ 552 uint8_t _wordCount; 553 554 /** 555 * @brief Two bytes of reserved data after the hex word count 556 */ 557 uint16_t _reserved2B; 558 559 /** 560 * @brief The total size of the SRC section, not including the section 561 * header. 562 */ 563 uint16_t _size; 564 565 /** 566 * @brief The SRC 'hex words'. 567 * 568 * In the spec these are referred to as SRC words 2 - 9 as words 0 and 1 569 * are filled by the 8 bytes of fields from above. 570 */ 571 std::array<uint32_t, numSRCHexDataWords> _hexData; 572 573 /** 574 * @brief The 32 byte ASCII character string of the SRC 575 * 576 * It is padded with spaces to fill the 32 bytes. 577 * An example is: 578 * "BD8D1234 " 579 * 580 * That first word is what is commonly referred to as the refcode, and 581 * sometimes also called an SRC. 582 */ 583 std::unique_ptr<src::AsciiString> _asciiString; 584 585 /** 586 * @brief The callouts subsection. 587 * 588 * Optional and only created if there are callouts. 589 */ 590 std::unique_ptr<src::Callouts> _callouts; 591 }; 592 593 } // namespace pels 594 } // namespace openpower 595