blob: d6f76e158d5727854cf2ec48e2a733a5937572dd [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 Spinlercb6b0592019-07-16 15:58:51 -0500307 private:
308 /**
309 * @brief Builds the section objects from a PEL data buffer
310 *
Matt Spinler07eefc52019-09-26 11:18:26 -0500311 * Note: The data parameter cannot be const for the same reasons
312 * as listed in the constructor.
313 *
314 * @param[in] data - The PEL data
Matt Spinlercb6b0592019-07-16 15:58:51 -0500315 * @param[in] obmcLogID - The OpenBMC event log ID to use for that
316 * field in the Private Header.
317 */
Matt Spinler07eefc52019-09-26 11:18:26 -0500318 void populateFromRawData(std::vector<uint8_t>& data, uint32_t obmcLogID);
Matt Spinlercb6b0592019-07-16 15:58:51 -0500319
320 /**
321 * @brief Flattens the PEL objects into the buffer
322 *
323 * @param[out] pelBuffer - What the data will be written to
324 */
Matt Spinler06885452019-11-06 10:35:42 -0600325 void flatten(std::vector<uint8_t>& pelBuffer) const;
Matt Spinlercb6b0592019-07-16 15:58:51 -0500326
327 /**
Matt Spinlerf1e85e22019-11-01 11:31:31 -0500328 * @brief Check that the PEL fields that need to be in agreement
329 * with each other are, and fix them up if necessary.
330 */
331 void checkRulesAndFix();
332
333 /**
Matt Spinleracb7c102020-01-10 13:49:22 -0600334 * @brief Returns a map of the section IDs that appear more than once
335 * in the PEL. The data value for each entry will be set to 0.
336 *
337 * @return std::map<uint16_t, size_t>
338 */
339 std::map<uint16_t, size_t> getPluralSections() const;
340
341 /**
Matt Spinler85f61a62020-06-03 16:28:55 -0500342 * @brief Adds the UserData section to this PEL object,
343 * shrinking it if necessary
344 *
345 * @param[in] userData - The section to add
346 *
347 * @return bool - If the section was added or not.
348 */
349 bool addUserDataSection(std::unique_ptr<UserData> userData);
350
351 /**
352 * @brief helper function for printing PELs.
353 * @param[in] Section& - section object reference
354 * @param[in] std::string - PEL string
355 * @param[in|out] pluralSections - Map used to track sections counts for
356 * when there is more than 1.
357 * @param[in] registry - Registry object reference
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800358 * @param[in] plugins - Vector of strings of plugins found in filesystem
359 * @param[in] creatorID - Creator Subsystem ID (only for UserData section)
Matt Spinler85f61a62020-06-03 16:28:55 -0500360 */
361 void printSectionInJSON(const Section& section, std::string& buf,
362 std::map<uint16_t, size_t>& pluralSections,
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800363 message::Registry& registry,
364 const std::vector<std::string>& plugins,
365 uint8_t creatorID = 0) const;
Matt Spinler85f61a62020-06-03 16:28:55 -0500366
367 /**
Matt Spinler5a90a952020-08-27 09:39:03 -0500368 * @brief Returns any callout JSON found in the FFDC files.
369 *
370 * Looks for an FFDC file that is JSON format and has the
371 * sub-type value set to 0xCA and returns its data as a JSON object.
372 *
373 * @param[in] ffdcFiles - FFCD files that go into UserData sections
374 *
375 * @return json - The callout JSON, or an empty object if not found
376 */
377 nlohmann::json getCalloutJSON(const PelFFDC& ffdcFiles);
378
379 /**
Sumit Kumar3e274432021-09-14 06:37:56 -0500380 * @brief Update terminate bit in primary SRC section to this PEL object is
381 * severity set to 0x51 = critical error, system termination
382 */
383 void updateTerminateBitInSRCSection();
384
385 /**
Matt Spinler9d921092022-12-15 11:54:49 -0600386 * @brief Adds journal data to the PEL as UserData sections
387 * if specified to in the message registry.
388 *
389 * @param regEntry - The registry entry
390 * @param journal - The journal object
391 */
392 void addJournalSections(const message::Entry& regEntry,
393 const JournalBase& journal);
394
395 /**
Matt Spinlercb6b0592019-07-16 15:58:51 -0500396 * @brief The PEL Private Header section
397 */
398 std::unique_ptr<PrivateHeader> _ph;
399
400 /**
401 * @brief The PEL User Header section
402 */
403 std::unique_ptr<UserHeader> _uh;
404
405 /**
Matt Spinler131870c2019-09-25 13:29:04 -0500406 * @brief Holds all sections by the PH and UH.
407 */
408 std::vector<std::unique_ptr<Section>> _optionalSections;
Aatir186ce8c2019-10-20 15:13:39 -0500409
410 /**
Matt Spinler6d663822020-01-22 14:50:46 -0600411 * @brief The maximum size a PEL can be in bytes.
412 */
413 static constexpr size_t _maxPELSize = 16384;
Matt Spinlercb6b0592019-07-16 15:58:51 -0500414};
415
Matt Spinlerafa857c2019-10-24 13:03:46 -0500416namespace util
417{
418
419/**
Matt Spinler85f61a62020-06-03 16:28:55 -0500420 * @brief Creates a UserData section object that contains JSON.
421 *
422 * @param[in] json - The JSON contents
423 *
424 * @return std::unique_ptr<UserData> - The UserData object
425 */
426std::unique_ptr<UserData> makeJSONUserDataSection(const nlohmann::json& json);
427
428/**
Matt Spinlerafa857c2019-10-24 13:03:46 -0500429 * @brief Create a UserData section containing the AdditionalData
430 * contents as a JSON string.
431 *
432 * @param[in] ad - The AdditionalData contents
433 *
434 * @return std::unique_ptr<UserData> - The section
435 */
436std::unique_ptr<UserData> makeADUserDataSection(const AdditionalData& ad);
437
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600438/**
439 * @brief Create a UserData section containing various useful pieces
440 * of system information as a JSON string.
441 *
442 * @param[in] ad - The AdditionalData contents
443 * @param[in] dataIface - The data interface object
George Liu9ac0d9b2022-07-15 10:57:38 +0800444 * @param[in] addUptime - Whether to add the uptime attribute the default is
445 * true
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600446 *
447 * @return std::unique_ptr<UserData> - The section
448 */
449std::unique_ptr<UserData>
450 makeSysInfoUserDataSection(const AdditionalData& ad,
George Liu9ac0d9b2022-07-15 10:57:38 +0800451 const DataInterfaceBase& dataIface,
452 bool addUptime = true);
Matt Spinler56ad2a02020-03-26 14:00:52 -0500453
454/**
Matt Spinler5a90a952020-08-27 09:39:03 -0500455 * @brief Reads data from an opened file descriptor.
456 *
457 * @param[in] fd - The FD to read from
458 *
459 * @return std::vector<uint8_t> - The data read
460 */
461std::vector<uint8_t> readFD(int fd);
462
463/**
Matt Spinler56ad2a02020-03-26 14:00:52 -0500464 * @brief Create a UserData section that contains the data in the file
465 * pointed to by the file descriptor passed in.
466 *
467 * @param[in] componentID - The component ID of the PEL creator
468 * @param[in] file - The FFDC file information
469 */
470std::unique_ptr<UserData> makeFFDCuserDataSection(uint16_t componentID,
471 const PelFFDCfile& file);
Matt Spinler9d921092022-12-15 11:54:49 -0600472
473/**
474 * @brief Flattens a vector of strings into a vector of bytes suitable
475 * for storing in a PEL section.
476 *
477 * Adds a newline character after each string.
478 *
479 * @param lines - The vector of strings to convert
480 *
481 * @return std::vector<uint8_t> - The flattened data
482 */
483std::vector<uint8_t> flattenLines(const std::vector<std::string>& lines);
484
Matt Spinlerafa857c2019-10-24 13:03:46 -0500485} // namespace util
486
Matt Spinlercb6b0592019-07-16 15:58:51 -0500487} // namespace pels
488} // namespace openpower