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