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     SRC() = delete;
61     ~SRC() = default;
62     SRC(const SRC&) = delete;
63     SRC& operator=(const SRC&) = delete;
64     SRC(SRC&&) = delete;
65     SRC& operator=(SRC&&) = delete;
66 
67     /**
68      * @brief Constructor
69      *
70      * Fills in this class's data fields from the stream.
71      *
72      * @param[in] pel - the PEL data stream
73      */
74     explicit SRC(Stream& pel);
75 
76     /**
77      * @brief Constructor
78      *
79      * Creates the section with data from the PEL message registry entry for
80      * this error, along with the AdditionalData property contents from the
81      * corresponding event log.
82      *
83      * @param[in] regEntry - The message registry entry for this event log
84      * @param[in] additionalData - The AdditionalData properties in this event
85      *                             log
86      * @param[in] dataIface - The DataInterface object
87      */
88     SRC(const message::Entry& regEntry, const AdditionalData& additionalData,
89         const DataInterfaceBase& dataIface);
90 
91     /**
92      * @brief Flatten the section into the stream
93      *
94      * @param[in] stream - The stream to write to
95      */
96     void flatten(Stream& stream) const override;
97 
98     /**
99      * @brief Returns the SRC version, which is a different field
100      *        than the version byte in the section header.
101      *
102      * @return uint8_t
103      */
104     uint8_t version() const
105     {
106         return _version;
107     }
108 
109     /**
110      * @brief Returns the flags byte
111      *
112      * @return uint8_t
113      */
114     uint8_t flags() const
115     {
116         return _flags;
117     }
118 
119     /**
120      * @brief Returns the hex data word count.
121      *
122      * Even though there always 8 words, this returns 9 due to previous
123      * SRC version formats.
124      *
125      * @return uint8_t
126      */
127     uint8_t hexWordCount() const
128     {
129         return _wordCount;
130     }
131 
132     /**
133      * @brief Returns the size of the SRC section, not including the header.
134      *
135      * @return uint16_t
136      */
137     uint16_t size() const
138     {
139         return _size;
140     }
141 
142     /**
143      * @brief Returns the 8 hex data words.
144      *
145      * @return const std::array<uint32_t, numSRCHexDataWords>&
146      */
147     const std::array<uint32_t, numSRCHexDataWords>& hexwordData() const
148     {
149         return _hexData;
150     }
151 
152     /**
153      * @brief Returns the ASCII string
154      *
155      * @return std::string
156      */
157     std::string asciiString() const
158     {
159         return _asciiString->get();
160     }
161 
162     /**
163      * @brief Returns the callouts subsection
164      *
165      * If no callouts, this unique_ptr will be empty
166      *
167      * @return  const std::unique_ptr<src::Callouts>&
168      */
169     const std::unique_ptr<src::Callouts>& callouts() const
170     {
171         return _callouts;
172     }
173 
174     /**
175      * @brief Returns the size of this section when flattened into a PEL
176      *
177      * @return size_t - the size of the section
178      */
179     size_t flattenedSize() const
180     {
181         return _header.size;
182     }
183 
184     /**
185      * @brief Says if this SRC has additional subsections in it
186      *
187      * Note: The callouts section is the only possible subsection.
188      *
189      * @return bool
190      */
191     inline bool hasAdditionalSections() const
192     {
193         return _flags & additionalSections;
194     }
195 
196     /**
197      * @brief Indicates if this event log is for a power fault.
198      *
199      * This comes from a field in the message registry for BMC
200      * generated PELs.
201      *
202      * @return bool
203      */
204     inline bool isPowerFaultEvent() const
205     {
206         return _flags & powerFaultEvent;
207     }
208 
209     /**
210      * @brief Get the _hexData[] index to use based on the corresponding
211      *        SRC word number.
212      *
213      * Converts the specification nomenclature to this data structure.
214      * See the _hexData documentation below for more information.
215      *
216      * @param[in] wordNum - The SRC word number, as defined by the spec.
217      *
218      * @return size_t The corresponding index into _hexData.
219      */
220     inline size_t getWordIndexFromWordNum(size_t wordNum) const
221     {
222         assert(wordNum >= 2 && wordNum <= 9);
223         return wordNum - 2;
224     }
225 
226     /**
227      * @brief Get section in JSON.
228      * @param[in] registry - Registry object reference
229      * @return std::optional<std::string> - SRC section's JSON
230      */
231     std::optional<std::string>
232         getJSON(message::Registry& registry) const override;
233 
234     /**
235      * @brief Get error details based on refcode and hexwords
236      * @param[in] registry - Registry object
237      * @param[in] type - detail level enum value : single message or full json
238      * @param[in] toCache - boolean to cache registry in memory, default=false
239      * @return std::optional<std::string> - Error details
240      */
241     std::optional<std::string> getErrorDetails(message::Registry& registry,
242                                                DetailLevel type,
243                                                bool toCache = false) const;
244 
245     /**
246      * @brief Says if this SRC was created by the BMC (i.e. this code).
247      *
248      * @return bool - If created by the BMC or not
249      */
250     bool isBMCSRC() const;
251 
252   private:
253     /**
254      * @brief Fills in the user defined hex words from the
255      *        AdditionalData fields.
256      *
257      * When creating this section from a message registry entry,
258      * that entry has a field that says which AdditionalData property
259      * fields to use to fill in the user defined hex data words 6-9
260      * (which correspond to hexData words 4-7).
261      *
262      * For example, given that AdditionalData is a map of string keys
263      * to string values, find the AdditionalData value for AdditionalData
264      * key X, convert it to a uint32_t, and save it in user data word Y.
265      *
266      * @param[in] regEntry - The message registry entry for the error
267      * @param[in] additionalData - The AdditionalData map
268      */
269     void setUserDefinedHexWords(const message::Entry& regEntry,
270                                 const AdditionalData& additionalData);
271     /**
272      * @brief Fills in the object from the stream data
273      *
274      * @param[in] stream - The stream to read from
275      */
276     void unflatten(Stream& stream);
277 
278     /**
279      * @brief Says if the word number is in the range of user defined words.
280      *
281      * This is only used for BMC generated SRCs, where words 6 - 9 are the
282      * user defined ones, meaning that setUserDefinedHexWords() will be
283      * used to fill them in based on the contents of the OpenBMC event log.
284      *
285      * @param[in] wordNum - The SRC word number, as defined by the spec.
286      *
287      * @return bool - If this word number can be filled in by the creator.
288      */
289     inline bool isUserDefinedWord(size_t wordNum) const
290     {
291         return (wordNum >= 6) && (wordNum <= 9);
292     }
293 
294     /**
295      * @brief Sets the SRC format byte in the hex word data.
296      */
297     inline void setBMCFormat()
298     {
299         _hexData[0] |= bmcSRCFormat;
300     }
301 
302     /**
303      * @brief Sets the hex word field that specifies which BMC
304      *        (primary vs backup) created the error.
305      *
306      * Can be hardcoded until there are systems with redundant BMCs.
307      */
308     inline void setBMCPosition()
309     {
310         _hexData[1] |= primaryBMCPosition;
311     }
312 
313     /**
314      * @brief Sets the motherboard CCIN hex word field
315      *
316      * @param[in] dataIface - The DataInterface object
317      */
318     void setMotherboardCCIN(const DataInterfaceBase& dataIface);
319 
320     /**
321      * @brief Validates the section contents
322      *
323      * Updates _valid (in Section) with the results.
324      */
325     void validate() override;
326 
327     /**
328      * @brief Get error description from message registry
329      * @param[in] regEntry - The message registry entry for the error
330      * @return std::optional<std::string> - Error message
331      */
332     std::optional<std::string>
333         getErrorMessage(const message::Entry& regEntry) const;
334 
335     /**
336      * @brief Get Callout info in JSON
337      * @return std::optional<std::string> - Callout details
338      */
339     std::optional<std::string> getCallouts() const;
340 
341     /**
342      * @brief The SRC version field
343      */
344     uint8_t _version;
345 
346     /**
347      * @brief The SRC flags field
348      */
349     uint8_t _flags;
350 
351     /**
352      * @brief A byte of reserved data after the flags field
353      */
354     uint8_t _reserved1B;
355 
356     /**
357      * @brief The hex data word count.
358      *
359      * To be compatible with previous versions of SRCs, this is
360      * number of hex words (8) + 1 = 9.
361      */
362     uint8_t _wordCount;
363 
364     /**
365      * @brief Two bytes of reserved data after the hex word count
366      */
367     uint16_t _reserved2B;
368 
369     /**
370      * @brief The total size of the SRC section, not including the section
371      *        header.
372      */
373     uint16_t _size;
374 
375     /**
376      * @brief The SRC 'hex words'.
377      *
378      * In the spec these are referred to as SRC words 2 - 9 as words 0 and 1
379      * are filled by the 8 bytes of fields from above.
380      */
381     std::array<uint32_t, numSRCHexDataWords> _hexData;
382 
383     /**
384      * @brief The 32 byte ASCII character string of the SRC
385      *
386      * It is padded with spaces to fill the 32 bytes.
387      * An example is:
388      * "BD8D1234                        "
389      *
390      * That first word is what is commonly referred to as the refcode, and
391      * sometimes also called an SRC.
392      */
393     std::unique_ptr<src::AsciiString> _asciiString;
394 
395     /**
396      * @brief The callouts subsection.
397      *
398      * Optional and only created if there are callouts.
399      */
400     std::unique_ptr<src::Callouts> _callouts;
401 };
402 
403 } // namespace pels
404 } // namespace openpower
405