blob: f6ff16593f5bad91f34845bf50263b3ef47c952c [file] [log] [blame]
Matt Spinlercb6b0592019-07-16 15:58:51 -05001#pragma once
2
Matt Spinlerb8323632019-09-20 15:11:04 -05003#include "additional_data.hpp"
Matt Spinleraa659472019-10-23 09:26:48 -05004#include "data_interface.hpp"
Matt Spinler9d921092022-12-15 11:54:49 -06005#include "journal.hpp"
Matt Spinlercb6b0592019-07-16 15:58:51 -05006#include "private_header.hpp"
Matt Spinlerb8323632019-09-20 15:11:04 -05007#include "registry.hpp"
Matt Spinlerbd716f02019-10-15 10:54:11 -05008#include "src.hpp"
Matt Spinlerafa857c2019-10-24 13:03:46 -05009#include "user_data.hpp"
Matt Spinler56ad2a02020-03-26 14:00:52 -050010#include "user_data_formats.hpp"
Matt Spinlercb6b0592019-07-16 15:58:51 -050011#include "user_header.hpp"
12
13#include <memory>
14#include <vector>
15
16namespace openpower
17{
18namespace pels
19{
20
Matt Spinler56ad2a02020-03-26 14:00:52 -050021/**
22 * @brief Contains information about an FFDC file.
23 */
24struct PelFFDCfile
25{
26 UserDataFormat format;
27 uint8_t subType;
28 uint8_t version;
29 int fd;
30};
31
32using PelFFDC = std::vector<PelFFDCfile>;
33
Jayanth Othayoth1ddf1e82021-06-04 09:00:54 -050034constexpr uint8_t jsonCalloutSubtype = 0xCA;
35
Matt Spinlercb6b0592019-07-16 15:58:51 -050036/** @class PEL
37 *
38 * @brief This class represents a specific event log format referred to as a
39 * Platform Event Log.
40 *
41 * Every field in a PEL are in structures call sections, of which there are
42 * several types. Some sections are required, and some are optional. In some
43 * cases there may be more than one instance of a section type.
44 *
45 * The only two required sections for every type of PEL are the Private Header
46 * section and User Header section, which must be in the first and second
47 * positions, respectively.
48 *
49 * Every section starts with an 8 byte section header, which has the section
50 * size and type, among other things.
51 *
52 * This class represents all sections with objects.
53 *
Matt Spinlerbd716f02019-10-15 10:54:11 -050054 * The class can be constructed:
55 * - From a full formed flattened PEL.
56 * - From scratch based on an OpenBMC event and its corresponding PEL message
57 * registry entry.
Matt Spinlerb8323632019-09-20 15:11:04 -050058 *
Matt Spinlercb6b0592019-07-16 15:58:51 -050059 * The data() method allows one to retrieve the PEL as a vector<uint8_t>. This
60 * is the format in which it is stored and transmitted.
61 */
62class PEL
63{
64 public:
65 PEL() = delete;
66 ~PEL() = default;
67 PEL(const PEL&) = delete;
68 PEL& operator=(const PEL&) = delete;
69 PEL(PEL&&) = delete;
70 PEL& operator=(PEL&&) = delete;
71
72 /**
73 * @brief Constructor
74 *
75 * Build a PEL from raw data.
76 *
Matt Spinler07eefc52019-09-26 11:18:26 -050077 * Note: Neither this nor the following constructor can take a const vector&
78 * because the Stream class that is used to read from the vector cannot take
79 * a const. The alternative is to make a copy of the data, but as PELs can
80 * be up to 16KB that is undesireable.
81 *
Matt Spinlercb6b0592019-07-16 15:58:51 -050082 * @param[in] data - The PEL data
83 */
Matt Spinler45796e82022-07-01 11:25:27 -050084 explicit PEL(std::vector<uint8_t>& data);
Matt Spinlercb6b0592019-07-16 15:58:51 -050085
86 /**
87 * @brief Constructor
88 *
89 * Build a PEL from the raw data.
90 *
91 * @param[in] data - the PEL data
92 * @param[in] obmcLogID - the corresponding OpenBMC event log ID
93 */
Matt Spinler07eefc52019-09-26 11:18:26 -050094 PEL(std::vector<uint8_t>& data, uint32_t obmcLogID);
Matt Spinlercb6b0592019-07-16 15:58:51 -050095
96 /**
Matt Spinlerb8323632019-09-20 15:11:04 -050097 * @brief Constructor
98 *
99 * Creates a PEL from an OpenBMC event log and its message
100 * registry entry.
101 *
102 * @param[in] entry - The message registry entry for this error
103 * @param[in] obmcLogID - ID of corresponding OpenBMC event log
104 * @param[in] timestamp - Timestamp from the event log
105 * @param[in] severity - Severity from the event log
Matt Spinlerbd716f02019-10-15 10:54:11 -0500106 * @param[in] additionalData - The AdditionalData contents
Matt Spinler56ad2a02020-03-26 14:00:52 -0500107 * @param[in] ffdcFiles - FFCD files that go into UserData sections
Matt Spinleraa659472019-10-23 09:26:48 -0500108 * @param[in] dataIface - The data interface object
Matt Spinler9d921092022-12-15 11:54:49 -0600109 * @param[in] journal - The journal object
Matt Spinlerb8323632019-09-20 15:11:04 -0500110 */
111 PEL(const openpower::pels::message::Entry& entry, uint32_t obmcLogID,
Matt Spinlerbd716f02019-10-15 10:54:11 -0500112 uint64_t timestamp, phosphor::logging::Entry::Level severity,
Matt Spinler56ad2a02020-03-26 14:00:52 -0500113 const AdditionalData& additionalData, const PelFFDC& ffdcFiles,
Matt Spinler9d921092022-12-15 11:54:49 -0600114 const DataInterfaceBase& dataIface, const JournalBase& journal);
Matt Spinlerb8323632019-09-20 15:11:04 -0500115
116 /**
Matt Spinlercb6b0592019-07-16 15:58:51 -0500117 * @brief Convenience function to return the log ID field from the
118 * Private Header section.
119 *
120 * @return uint32_t - the ID
121 */
122 uint32_t id() const
123 {
124 return _ph->id();
125 }
126
127 /**
128 * @brief Convenience function to return the PLID field from the
129 * Private Header section.
130 *
131 * @return uint32_t - the PLID
132 */
133 uint32_t plid() const
134 {
135 return _ph->plid();
136 }
137
138 /**
139 * @brief Convenience function to return the OpenBMC event log ID field
140 * from the Private Header section.
141 *
142 * @return uint32_t - the OpenBMC event log ID
143 */
144 uint32_t obmcLogID() const
145 {
146 return _ph->obmcLogID();
147 }
148
149 /**
150 * @brief Convenience function to return the commit time field from
151 * the Private Header section.
152 *
153 * @return BCDTime - the timestamp
154 */
155 BCDTime commitTime() const
156 {
157 return _ph->commitTimestamp();
158 }
159
160 /**
161 * @brief Convenience function to return the create time field from
162 * the Private Header section.
163 *
164 * @return BCDTime - the timestamp
165 */
166 BCDTime createTime() const
167 {
168 return _ph->createTimestamp();
169 }
170
171 /**
172 * @brief Gives access to the Private Header section class
173 *
Matt Spinler97d19b42019-10-29 11:34:03 -0500174 * @return const PrivateHeader& - the private header
Matt Spinlercb6b0592019-07-16 15:58:51 -0500175 */
Matt Spinler97d19b42019-10-29 11:34:03 -0500176 const PrivateHeader& privateHeader() const
Matt Spinlercb6b0592019-07-16 15:58:51 -0500177 {
Matt Spinler97d19b42019-10-29 11:34:03 -0500178 return *_ph;
Matt Spinlercb6b0592019-07-16 15:58:51 -0500179 }
180
181 /**
182 * @brief Gives access to the User Header section class
183 *
Matt Spinler97d19b42019-10-29 11:34:03 -0500184 * @return const UserHeader& - the user header
Matt Spinlercb6b0592019-07-16 15:58:51 -0500185 */
Matt Spinler97d19b42019-10-29 11:34:03 -0500186 const UserHeader& userHeader() const
Matt Spinlercb6b0592019-07-16 15:58:51 -0500187 {
Matt Spinler97d19b42019-10-29 11:34:03 -0500188 return *_uh;
Matt Spinlercb6b0592019-07-16 15:58:51 -0500189 }
190
191 /**
Matt Spinlerbd716f02019-10-15 10:54:11 -0500192 * @brief Gives access to the primary SRC's section class
193 *
194 * This is technically an optional section, so the return
195 * value is an std::optional<SRC*>.
196 *
197 * @return std::optional<SRC*> - the SRC section object
198 */
199 std::optional<SRC*> primarySRC() const;
200
201 /**
Matt Spinler131870c2019-09-25 13:29:04 -0500202 * @brief Returns the optional sections, which is everything but
203 * the Private and User Headers.
204 *
205 * @return const std::vector<std::unique_ptr<Section>>&
206 */
207 const std::vector<std::unique_ptr<Section>>& optionalSections() const
208 {
209 return _optionalSections;
210 }
211
212 /**
Matt Spinlercb6b0592019-07-16 15:58:51 -0500213 * @brief Returns the PEL data.
214 *
215 * @return std::vector<uint8_t> - the raw PEL data
216 */
Matt Spinler06885452019-11-06 10:35:42 -0600217 std::vector<uint8_t> data() const;
Matt Spinlercb6b0592019-07-16 15:58:51 -0500218
219 /**
Matt Spinlerf1b46ff2020-01-22 14:10:04 -0600220 * @brief Returns the size of the PEL
221 *
222 * @return size_t The PEL size in bytes
223 */
224 size_t size() const;
225
226 /**
Matt Spinlercb6b0592019-07-16 15:58:51 -0500227 * @brief Says if the PEL is valid (the sections are all valid)
228 *
229 * @return bool - if the PEL is valid
230 */
231 bool valid() const;
232
233 /**
234 * @brief Sets the commit timestamp to the current time
235 */
236 void setCommitTime();
237
238 /**
239 * @brief Sets the error log ID field to a unique ID.
240 */
241 void assignID();
242
Aatir186ce8c2019-10-20 15:13:39 -0500243 /**
244 * @brief Output a PEL in JSON.
Harisuddin Mohamed Isaa214ed32020-02-28 15:58:23 +0800245 * @param[in] registry - Registry object reference
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800246 * @param[in] plugins - Vector of strings of plugins found in filesystem
Aatir186ce8c2019-10-20 15:13:39 -0500247 */
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800248 void toJSON(message::Registry& registry,
249 const std::vector<std::string>& plugins) const;
Aatir186ce8c2019-10-20 15:13:39 -0500250
Matt Spinlerf38ce982019-11-07 13:25:53 -0600251 /**
252 * @brief Sets the host transmission state in the User Header
253 *
254 * @param[in] state - The state value
255 */
256 void setHostTransmissionState(TransmissionState state)
257 {
258 _uh->setHostTransmissionState(static_cast<uint8_t>(state));
259 }
260
261 /**
262 * @brief Returns the host transmission state
263 *
264 * @return HostTransmissionState - The state
265 */
266 TransmissionState hostTransmissionState() const
267 {
268 return static_cast<TransmissionState>(_uh->hostTransmissionState());
269 }
270
271 /**
272 * @brief Sets the HMC transmission state in the User Header
273 *
274 * @param[in] state - The state value
275 */
276 void setHMCTransmissionState(TransmissionState state)
277 {
278 _uh->setHMCTransmissionState(static_cast<uint8_t>(state));
279 }
280
281 /**
282 * @brief Returns the HMC transmission state
283 *
284 * @return HMCTransmissionState - The state
285 */
286 TransmissionState hmcTransmissionState() const
287 {
288 return static_cast<TransmissionState>(_uh->hmcTransmissionState());
289 }
290
Andrew Geissler44fc3162020-07-09 09:21:31 -0500291 /**
Andrew Geisslerf8e750d2022-01-14 14:56:13 -0600292 * @brief Returns true if a hardware callout is present in the primary SRC
Andrew Geissler44fc3162020-07-09 09:21:31 -0500293 *
Andrew Geisslerf8e750d2022-01-14 14:56:13 -0600294 * @return true if hardware callout present, false otherwise
Andrew Geissler44fc3162020-07-09 09:21:31 -0500295 */
Andrew Geisslerf8e750d2022-01-14 14:56:13 -0600296 bool isHwCalloutPresent() const;
Andrew Geissler44fc3162020-07-09 09:21:31 -0500297
Sumit Kumar3160a542021-04-26 08:07:04 -0500298 /**
299 * @brief Updates the system info data into HB extended user
300 * data section to this PEL object
301 *
302 * @param[in] dataIface - The data interface object
303 */
304 void updateSysInfoInExtendedUserDataSection(
305 const DataInterfaceBase& dataIface);
306
Matt Spinler8e65f4e2023-05-02 13:40:08 -0500307 /**
308 * @brief Return the deconfig flag from hex data word 5 of BMC and
309 * hostboot PELs.
310 *
311 * This only applies to BMC and hostboot PELs because only those
312 * SRC formats have this flag defined.
313 *
314 * @return bool - If the 'one or more resources are deconfigured'
315 * flag is set.
316 */
317 bool getDeconfigFlag() const;
318
319 /**
320 * @brief Return the guard flag from hex data word 5 of BMC and
321 * hostboot PELs.
322 *
323 * This only applies to BMC and hostboot PELs because only those
324 * SRC formats have this flag defined.
325 *
326 * @return bool - If the 'one or more resources are guarded'
327 * flag is set.
328 */
329 bool getGuardFlag() const;
330
Matt Spinlercb6b0592019-07-16 15:58:51 -0500331 private:
332 /**
333 * @brief Builds the section objects from a PEL data buffer
334 *
Matt Spinler07eefc52019-09-26 11:18:26 -0500335 * Note: The data parameter cannot be const for the same reasons
336 * as listed in the constructor.
337 *
338 * @param[in] data - The PEL data
Matt Spinlercb6b0592019-07-16 15:58:51 -0500339 * @param[in] obmcLogID - The OpenBMC event log ID to use for that
340 * field in the Private Header.
341 */
Matt Spinler07eefc52019-09-26 11:18:26 -0500342 void populateFromRawData(std::vector<uint8_t>& data, uint32_t obmcLogID);
Matt Spinlercb6b0592019-07-16 15:58:51 -0500343
344 /**
345 * @brief Flattens the PEL objects into the buffer
346 *
347 * @param[out] pelBuffer - What the data will be written to
348 */
Matt Spinler06885452019-11-06 10:35:42 -0600349 void flatten(std::vector<uint8_t>& pelBuffer) const;
Matt Spinlercb6b0592019-07-16 15:58:51 -0500350
351 /**
Matt Spinlerf1e85e22019-11-01 11:31:31 -0500352 * @brief Check that the PEL fields that need to be in agreement
353 * with each other are, and fix them up if necessary.
354 */
355 void checkRulesAndFix();
356
357 /**
Matt Spinleracb7c102020-01-10 13:49:22 -0600358 * @brief Returns a map of the section IDs that appear more than once
359 * in the PEL. The data value for each entry will be set to 0.
360 *
361 * @return std::map<uint16_t, size_t>
362 */
363 std::map<uint16_t, size_t> getPluralSections() const;
364
365 /**
Matt Spinler85f61a62020-06-03 16:28:55 -0500366 * @brief Adds the UserData section to this PEL object,
367 * shrinking it if necessary
368 *
369 * @param[in] userData - The section to add
370 *
371 * @return bool - If the section was added or not.
372 */
373 bool addUserDataSection(std::unique_ptr<UserData> userData);
374
375 /**
376 * @brief helper function for printing PELs.
377 * @param[in] Section& - section object reference
378 * @param[in] std::string - PEL string
379 * @param[in|out] pluralSections - Map used to track sections counts for
380 * when there is more than 1.
381 * @param[in] registry - Registry object reference
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800382 * @param[in] plugins - Vector of strings of plugins found in filesystem
383 * @param[in] creatorID - Creator Subsystem ID (only for UserData section)
Matt Spinler85f61a62020-06-03 16:28:55 -0500384 */
385 void printSectionInJSON(const Section& section, std::string& buf,
386 std::map<uint16_t, size_t>& pluralSections,
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800387 message::Registry& registry,
388 const std::vector<std::string>& plugins,
389 uint8_t creatorID = 0) const;
Matt Spinler85f61a62020-06-03 16:28:55 -0500390
391 /**
Matt Spinler5a90a952020-08-27 09:39:03 -0500392 * @brief Returns any callout JSON found in the FFDC files.
393 *
394 * Looks for an FFDC file that is JSON format and has the
395 * sub-type value set to 0xCA and returns its data as a JSON object.
396 *
397 * @param[in] ffdcFiles - FFCD files that go into UserData sections
398 *
399 * @return json - The callout JSON, or an empty object if not found
400 */
401 nlohmann::json getCalloutJSON(const PelFFDC& ffdcFiles);
402
403 /**
Sumit Kumar3e274432021-09-14 06:37:56 -0500404 * @brief Update terminate bit in primary SRC section to this PEL object is
405 * severity set to 0x51 = critical error, system termination
406 */
407 void updateTerminateBitInSRCSection();
408
409 /**
Matt Spinler9d921092022-12-15 11:54:49 -0600410 * @brief Adds journal data to the PEL as UserData sections
411 * if specified to in the message registry.
412 *
413 * @param regEntry - The registry entry
414 * @param journal - The journal object
415 */
416 void addJournalSections(const message::Entry& regEntry,
417 const JournalBase& journal);
418
419 /**
Matt Spinlercb6b0592019-07-16 15:58:51 -0500420 * @brief The PEL Private Header section
421 */
422 std::unique_ptr<PrivateHeader> _ph;
423
424 /**
425 * @brief The PEL User Header section
426 */
427 std::unique_ptr<UserHeader> _uh;
428
429 /**
Matt Spinler131870c2019-09-25 13:29:04 -0500430 * @brief Holds all sections by the PH and UH.
431 */
432 std::vector<std::unique_ptr<Section>> _optionalSections;
Aatir186ce8c2019-10-20 15:13:39 -0500433
434 /**
Matt Spinler6d663822020-01-22 14:50:46 -0600435 * @brief The maximum size a PEL can be in bytes.
436 */
437 static constexpr size_t _maxPELSize = 16384;
Matt Spinlercb6b0592019-07-16 15:58:51 -0500438};
439
Matt Spinlerafa857c2019-10-24 13:03:46 -0500440namespace util
441{
442
443/**
Matt Spinler85f61a62020-06-03 16:28:55 -0500444 * @brief Creates a UserData section object that contains JSON.
445 *
446 * @param[in] json - The JSON contents
447 *
448 * @return std::unique_ptr<UserData> - The UserData object
449 */
450std::unique_ptr<UserData> makeJSONUserDataSection(const nlohmann::json& json);
451
452/**
Matt Spinlerafa857c2019-10-24 13:03:46 -0500453 * @brief Create a UserData section containing the AdditionalData
454 * contents as a JSON string.
455 *
456 * @param[in] ad - The AdditionalData contents
457 *
458 * @return std::unique_ptr<UserData> - The section
459 */
460std::unique_ptr<UserData> makeADUserDataSection(const AdditionalData& ad);
461
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600462/**
463 * @brief Create a UserData section containing various useful pieces
464 * of system information as a JSON string.
465 *
466 * @param[in] ad - The AdditionalData contents
467 * @param[in] dataIface - The data interface object
George Liu9ac0d9b2022-07-15 10:57:38 +0800468 * @param[in] addUptime - Whether to add the uptime attribute the default is
469 * true
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600470 *
471 * @return std::unique_ptr<UserData> - The section
472 */
473std::unique_ptr<UserData>
474 makeSysInfoUserDataSection(const AdditionalData& ad,
George Liu9ac0d9b2022-07-15 10:57:38 +0800475 const DataInterfaceBase& dataIface,
476 bool addUptime = true);
Matt Spinler56ad2a02020-03-26 14:00:52 -0500477
478/**
Matt Spinler5a90a952020-08-27 09:39:03 -0500479 * @brief Reads data from an opened file descriptor.
480 *
481 * @param[in] fd - The FD to read from
482 *
483 * @return std::vector<uint8_t> - The data read
484 */
485std::vector<uint8_t> readFD(int fd);
486
487/**
Matt Spinler56ad2a02020-03-26 14:00:52 -0500488 * @brief Create a UserData section that contains the data in the file
489 * pointed to by the file descriptor passed in.
490 *
491 * @param[in] componentID - The component ID of the PEL creator
492 * @param[in] file - The FFDC file information
493 */
494std::unique_ptr<UserData> makeFFDCuserDataSection(uint16_t componentID,
495 const PelFFDCfile& file);
Matt Spinler9d921092022-12-15 11:54:49 -0600496
497/**
498 * @brief Flattens a vector of strings into a vector of bytes suitable
499 * for storing in a PEL section.
500 *
501 * Adds a newline character after each string.
502 *
503 * @param lines - The vector of strings to convert
504 *
505 * @return std::vector<uint8_t> - The flattened data
506 */
507std::vector<uint8_t> flattenLines(const std::vector<std::string>& lines);
508
Matt Spinlerafa857c2019-10-24 13:03:46 -0500509} // namespace util
510
Matt Spinlercb6b0592019-07-16 15:58:51 -0500511} // namespace pels
512} // namespace openpower