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 The SRC version field
526      */
527     uint8_t _version;
528 
529     /**
530      * @brief The SRC flags field
531      */
532     uint8_t _flags;
533 
534     /**
535      * @brief A byte of reserved data after the flags field
536      */
537     uint8_t _reserved1B;
538 
539     /**
540      * @brief The hex data word count.
541      *
542      * To be compatible with previous versions of SRCs, this is
543      * number of hex words (8) + 1 = 9.
544      */
545     uint8_t _wordCount;
546 
547     /**
548      * @brief Two bytes of reserved data after the hex word count
549      */
550     uint16_t _reserved2B;
551 
552     /**
553      * @brief The total size of the SRC section, not including the section
554      *        header.
555      */
556     uint16_t _size;
557 
558     /**
559      * @brief The SRC 'hex words'.
560      *
561      * In the spec these are referred to as SRC words 2 - 9 as words 0 and 1
562      * are filled by the 8 bytes of fields from above.
563      */
564     std::array<uint32_t, numSRCHexDataWords> _hexData;
565 
566     /**
567      * @brief The 32 byte ASCII character string of the SRC
568      *
569      * It is padded with spaces to fill the 32 bytes.
570      * An example is:
571      * "BD8D1234                        "
572      *
573      * That first word is what is commonly referred to as the refcode, and
574      * sometimes also called an SRC.
575      */
576     std::unique_ptr<src::AsciiString> _asciiString;
577 
578     /**
579      * @brief The callouts subsection.
580      *
581      * Optional and only created if there are callouts.
582      */
583     std::unique_ptr<src::Callouts> _callouts;
584 };
585 
586 } // namespace pels
587 } // namespace openpower
588