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