blob: 649357f32d5de9148096cc98f46243fe15ecfa9e [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 Spinlercb6b0592019-07-16 15:58:51 -05005#include "private_header.hpp"
Matt Spinlerb8323632019-09-20 15:11:04 -05006#include "registry.hpp"
Matt Spinlerbd716f02019-10-15 10:54:11 -05007#include "src.hpp"
Matt Spinlerafa857c2019-10-24 13:03:46 -05008#include "user_data.hpp"
Matt Spinler56ad2a02020-03-26 14:00:52 -05009#include "user_data_formats.hpp"
Matt Spinlercb6b0592019-07-16 15:58:51 -050010#include "user_header.hpp"
11
12#include <memory>
13#include <vector>
14
15namespace openpower
16{
17namespace pels
18{
19
Matt Spinler56ad2a02020-03-26 14:00:52 -050020/**
21 * @brief Contains information about an FFDC file.
22 */
23struct PelFFDCfile
24{
25 UserDataFormat format;
26 uint8_t subType;
27 uint8_t version;
28 int fd;
29};
30
31using PelFFDC = std::vector<PelFFDCfile>;
32
Jayanth Othayoth1ddf1e82021-06-04 09:00:54 -050033constexpr uint8_t jsonCalloutSubtype = 0xCA;
34
Matt Spinlercb6b0592019-07-16 15:58:51 -050035/** @class PEL
36 *
37 * @brief This class represents a specific event log format referred to as a
38 * Platform Event Log.
39 *
40 * Every field in a PEL are in structures call sections, of which there are
41 * several types. Some sections are required, and some are optional. In some
42 * cases there may be more than one instance of a section type.
43 *
44 * The only two required sections for every type of PEL are the Private Header
45 * section and User Header section, which must be in the first and second
46 * positions, respectively.
47 *
48 * Every section starts with an 8 byte section header, which has the section
49 * size and type, among other things.
50 *
51 * This class represents all sections with objects.
52 *
Matt Spinlerbd716f02019-10-15 10:54:11 -050053 * The class can be constructed:
54 * - From a full formed flattened PEL.
55 * - From scratch based on an OpenBMC event and its corresponding PEL message
56 * registry entry.
Matt Spinlerb8323632019-09-20 15:11:04 -050057 *
Matt Spinlercb6b0592019-07-16 15:58:51 -050058 * The data() method allows one to retrieve the PEL as a vector<uint8_t>. This
59 * is the format in which it is stored and transmitted.
60 */
61class PEL
62{
63 public:
64 PEL() = delete;
65 ~PEL() = default;
66 PEL(const PEL&) = delete;
67 PEL& operator=(const PEL&) = delete;
68 PEL(PEL&&) = delete;
69 PEL& operator=(PEL&&) = delete;
70
71 /**
72 * @brief Constructor
73 *
74 * Build a PEL from raw data.
75 *
Matt Spinler07eefc52019-09-26 11:18:26 -050076 * Note: Neither this nor the following constructor can take a const vector&
77 * because the Stream class that is used to read from the vector cannot take
78 * a const. The alternative is to make a copy of the data, but as PELs can
79 * be up to 16KB that is undesireable.
80 *
Matt Spinlercb6b0592019-07-16 15:58:51 -050081 * @param[in] data - The PEL data
82 */
Matt Spinler07eefc52019-09-26 11:18:26 -050083 PEL(std::vector<uint8_t>& data);
Matt Spinlercb6b0592019-07-16 15:58:51 -050084
85 /**
86 * @brief Constructor
87 *
88 * Build a PEL from the raw data.
89 *
90 * @param[in] data - the PEL data
91 * @param[in] obmcLogID - the corresponding OpenBMC event log ID
92 */
Matt Spinler07eefc52019-09-26 11:18:26 -050093 PEL(std::vector<uint8_t>& data, uint32_t obmcLogID);
Matt Spinlercb6b0592019-07-16 15:58:51 -050094
95 /**
Matt Spinlerb8323632019-09-20 15:11:04 -050096 * @brief Constructor
97 *
98 * Creates a PEL from an OpenBMC event log and its message
99 * registry entry.
100 *
101 * @param[in] entry - The message registry entry for this error
102 * @param[in] obmcLogID - ID of corresponding OpenBMC event log
103 * @param[in] timestamp - Timestamp from the event log
104 * @param[in] severity - Severity from the event log
Matt Spinlerbd716f02019-10-15 10:54:11 -0500105 * @param[in] additionalData - The AdditionalData contents
Matt Spinler56ad2a02020-03-26 14:00:52 -0500106 * @param[in] ffdcFiles - FFCD files that go into UserData sections
Matt Spinleraa659472019-10-23 09:26:48 -0500107 * @param[in] dataIface - The data interface object
Matt Spinlerb8323632019-09-20 15:11:04 -0500108 */
109 PEL(const openpower::pels::message::Entry& entry, uint32_t obmcLogID,
Matt Spinlerbd716f02019-10-15 10:54:11 -0500110 uint64_t timestamp, phosphor::logging::Entry::Level severity,
Matt Spinler56ad2a02020-03-26 14:00:52 -0500111 const AdditionalData& additionalData, const PelFFDC& ffdcFiles,
Matt Spinleraa659472019-10-23 09:26:48 -0500112 const DataInterfaceBase& dataIface);
Matt Spinlerb8323632019-09-20 15:11:04 -0500113
114 /**
Matt Spinlercb6b0592019-07-16 15:58:51 -0500115 * @brief Convenience function to return the log ID field from the
116 * Private Header section.
117 *
118 * @return uint32_t - the ID
119 */
120 uint32_t id() const
121 {
122 return _ph->id();
123 }
124
125 /**
126 * @brief Convenience function to return the PLID field from the
127 * Private Header section.
128 *
129 * @return uint32_t - the PLID
130 */
131 uint32_t plid() const
132 {
133 return _ph->plid();
134 }
135
136 /**
137 * @brief Convenience function to return the OpenBMC event log ID field
138 * from the Private Header section.
139 *
140 * @return uint32_t - the OpenBMC event log ID
141 */
142 uint32_t obmcLogID() const
143 {
144 return _ph->obmcLogID();
145 }
146
147 /**
148 * @brief Convenience function to return the commit time field from
149 * the Private Header section.
150 *
151 * @return BCDTime - the timestamp
152 */
153 BCDTime commitTime() const
154 {
155 return _ph->commitTimestamp();
156 }
157
158 /**
159 * @brief Convenience function to return the create time field from
160 * the Private Header section.
161 *
162 * @return BCDTime - the timestamp
163 */
164 BCDTime createTime() const
165 {
166 return _ph->createTimestamp();
167 }
168
169 /**
170 * @brief Gives access to the Private Header section class
171 *
Matt Spinler97d19b42019-10-29 11:34:03 -0500172 * @return const PrivateHeader& - the private header
Matt Spinlercb6b0592019-07-16 15:58:51 -0500173 */
Matt Spinler97d19b42019-10-29 11:34:03 -0500174 const PrivateHeader& privateHeader() const
Matt Spinlercb6b0592019-07-16 15:58:51 -0500175 {
Matt Spinler97d19b42019-10-29 11:34:03 -0500176 return *_ph;
Matt Spinlercb6b0592019-07-16 15:58:51 -0500177 }
178
179 /**
180 * @brief Gives access to the User Header section class
181 *
Matt Spinler97d19b42019-10-29 11:34:03 -0500182 * @return const UserHeader& - the user header
Matt Spinlercb6b0592019-07-16 15:58:51 -0500183 */
Matt Spinler97d19b42019-10-29 11:34:03 -0500184 const UserHeader& userHeader() const
Matt Spinlercb6b0592019-07-16 15:58:51 -0500185 {
Matt Spinler97d19b42019-10-29 11:34:03 -0500186 return *_uh;
Matt Spinlercb6b0592019-07-16 15:58:51 -0500187 }
188
189 /**
Matt Spinlerbd716f02019-10-15 10:54:11 -0500190 * @brief Gives access to the primary SRC's section class
191 *
192 * This is technically an optional section, so the return
193 * value is an std::optional<SRC*>.
194 *
195 * @return std::optional<SRC*> - the SRC section object
196 */
197 std::optional<SRC*> primarySRC() const;
198
199 /**
Matt Spinler131870c2019-09-25 13:29:04 -0500200 * @brief Returns the optional sections, which is everything but
201 * the Private and User Headers.
202 *
203 * @return const std::vector<std::unique_ptr<Section>>&
204 */
205 const std::vector<std::unique_ptr<Section>>& optionalSections() const
206 {
207 return _optionalSections;
208 }
209
210 /**
Matt Spinlercb6b0592019-07-16 15:58:51 -0500211 * @brief Returns the PEL data.
212 *
213 * @return std::vector<uint8_t> - the raw PEL data
214 */
Matt Spinler06885452019-11-06 10:35:42 -0600215 std::vector<uint8_t> data() const;
Matt Spinlercb6b0592019-07-16 15:58:51 -0500216
217 /**
Matt Spinlerf1b46ff2020-01-22 14:10:04 -0600218 * @brief Returns the size of the PEL
219 *
220 * @return size_t The PEL size in bytes
221 */
222 size_t size() const;
223
224 /**
Matt Spinlercb6b0592019-07-16 15:58:51 -0500225 * @brief Says if the PEL is valid (the sections are all valid)
226 *
227 * @return bool - if the PEL is valid
228 */
229 bool valid() const;
230
231 /**
232 * @brief Sets the commit timestamp to the current time
233 */
234 void setCommitTime();
235
236 /**
237 * @brief Sets the error log ID field to a unique ID.
238 */
239 void assignID();
240
Aatir186ce8c2019-10-20 15:13:39 -0500241 /**
242 * @brief Output a PEL in JSON.
Harisuddin Mohamed Isaa214ed32020-02-28 15:58:23 +0800243 * @param[in] registry - Registry object reference
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800244 * @param[in] plugins - Vector of strings of plugins found in filesystem
Aatir186ce8c2019-10-20 15:13:39 -0500245 */
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800246 void toJSON(message::Registry& registry,
247 const std::vector<std::string>& plugins) const;
Aatir186ce8c2019-10-20 15:13:39 -0500248
Matt Spinlerf38ce982019-11-07 13:25:53 -0600249 /**
250 * @brief Sets the host transmission state in the User Header
251 *
252 * @param[in] state - The state value
253 */
254 void setHostTransmissionState(TransmissionState state)
255 {
256 _uh->setHostTransmissionState(static_cast<uint8_t>(state));
257 }
258
259 /**
260 * @brief Returns the host transmission state
261 *
262 * @return HostTransmissionState - The state
263 */
264 TransmissionState hostTransmissionState() const
265 {
266 return static_cast<TransmissionState>(_uh->hostTransmissionState());
267 }
268
269 /**
270 * @brief Sets the HMC transmission state in the User Header
271 *
272 * @param[in] state - The state value
273 */
274 void setHMCTransmissionState(TransmissionState state)
275 {
276 _uh->setHMCTransmissionState(static_cast<uint8_t>(state));
277 }
278
279 /**
280 * @brief Returns the HMC transmission state
281 *
282 * @return HMCTransmissionState - The state
283 */
284 TransmissionState hmcTransmissionState() const
285 {
286 return static_cast<TransmissionState>(_uh->hmcTransmissionState());
287 }
288
Andrew Geissler44fc3162020-07-09 09:21:31 -0500289 /**
290 * @brief Returns true if any callout is present in the primary SRC
291 *
292 * @return true if callout present, false otherwise
293 */
294 bool isCalloutPresent() const;
295
Sumit Kumar3160a542021-04-26 08:07:04 -0500296 /**
297 * @brief Updates the system info data into HB extended user
298 * data section to this PEL object
299 *
300 * @param[in] dataIface - The data interface object
301 */
302 void updateSysInfoInExtendedUserDataSection(
303 const DataInterfaceBase& dataIface);
304
Matt Spinlercb6b0592019-07-16 15:58:51 -0500305 private:
306 /**
307 * @brief Builds the section objects from a PEL data buffer
308 *
Matt Spinler07eefc52019-09-26 11:18:26 -0500309 * Note: The data parameter cannot be const for the same reasons
310 * as listed in the constructor.
311 *
312 * @param[in] data - The PEL data
Matt Spinlercb6b0592019-07-16 15:58:51 -0500313 * @param[in] obmcLogID - The OpenBMC event log ID to use for that
314 * field in the Private Header.
315 */
Matt Spinler07eefc52019-09-26 11:18:26 -0500316 void populateFromRawData(std::vector<uint8_t>& data, uint32_t obmcLogID);
Matt Spinlercb6b0592019-07-16 15:58:51 -0500317
318 /**
319 * @brief Flattens the PEL objects into the buffer
320 *
321 * @param[out] pelBuffer - What the data will be written to
322 */
Matt Spinler06885452019-11-06 10:35:42 -0600323 void flatten(std::vector<uint8_t>& pelBuffer) const;
Matt Spinlercb6b0592019-07-16 15:58:51 -0500324
325 /**
Matt Spinlerf1e85e22019-11-01 11:31:31 -0500326 * @brief Check that the PEL fields that need to be in agreement
327 * with each other are, and fix them up if necessary.
328 */
329 void checkRulesAndFix();
330
331 /**
Matt Spinleracb7c102020-01-10 13:49:22 -0600332 * @brief Returns a map of the section IDs that appear more than once
333 * in the PEL. The data value for each entry will be set to 0.
334 *
335 * @return std::map<uint16_t, size_t>
336 */
337 std::map<uint16_t, size_t> getPluralSections() const;
338
339 /**
Matt Spinler85f61a62020-06-03 16:28:55 -0500340 * @brief Adds the UserData section to this PEL object,
341 * shrinking it if necessary
342 *
343 * @param[in] userData - The section to add
344 *
345 * @return bool - If the section was added or not.
346 */
347 bool addUserDataSection(std::unique_ptr<UserData> userData);
348
349 /**
350 * @brief helper function for printing PELs.
351 * @param[in] Section& - section object reference
352 * @param[in] std::string - PEL string
353 * @param[in|out] pluralSections - Map used to track sections counts for
354 * when there is more than 1.
355 * @param[in] registry - Registry object reference
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800356 * @param[in] plugins - Vector of strings of plugins found in filesystem
357 * @param[in] creatorID - Creator Subsystem ID (only for UserData section)
Matt Spinler85f61a62020-06-03 16:28:55 -0500358 */
359 void printSectionInJSON(const Section& section, std::string& buf,
360 std::map<uint16_t, size_t>& pluralSections,
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800361 message::Registry& registry,
362 const std::vector<std::string>& plugins,
363 uint8_t creatorID = 0) const;
Matt Spinler85f61a62020-06-03 16:28:55 -0500364
365 /**
Matt Spinler5a90a952020-08-27 09:39:03 -0500366 * @brief Returns any callout JSON found in the FFDC files.
367 *
368 * Looks for an FFDC file that is JSON format and has the
369 * sub-type value set to 0xCA and returns its data as a JSON object.
370 *
371 * @param[in] ffdcFiles - FFCD files that go into UserData sections
372 *
373 * @return json - The callout JSON, or an empty object if not found
374 */
375 nlohmann::json getCalloutJSON(const PelFFDC& ffdcFiles);
376
377 /**
Sumit Kumar3e274432021-09-14 06:37:56 -0500378 * @brief Update terminate bit in primary SRC section to this PEL object is
379 * severity set to 0x51 = critical error, system termination
380 */
381 void updateTerminateBitInSRCSection();
382
383 /**
Matt Spinlercb6b0592019-07-16 15:58:51 -0500384 * @brief The PEL Private Header section
385 */
386 std::unique_ptr<PrivateHeader> _ph;
387
388 /**
389 * @brief The PEL User Header section
390 */
391 std::unique_ptr<UserHeader> _uh;
392
393 /**
Matt Spinler131870c2019-09-25 13:29:04 -0500394 * @brief Holds all sections by the PH and UH.
395 */
396 std::vector<std::unique_ptr<Section>> _optionalSections;
Aatir186ce8c2019-10-20 15:13:39 -0500397
398 /**
Matt Spinler6d663822020-01-22 14:50:46 -0600399 * @brief The maximum size a PEL can be in bytes.
400 */
401 static constexpr size_t _maxPELSize = 16384;
Matt Spinlercb6b0592019-07-16 15:58:51 -0500402};
403
Matt Spinlerafa857c2019-10-24 13:03:46 -0500404namespace util
405{
406
407/**
Matt Spinler85f61a62020-06-03 16:28:55 -0500408 * @brief Creates a UserData section object that contains JSON.
409 *
410 * @param[in] json - The JSON contents
411 *
412 * @return std::unique_ptr<UserData> - The UserData object
413 */
414std::unique_ptr<UserData> makeJSONUserDataSection(const nlohmann::json& json);
415
416/**
Matt Spinlerafa857c2019-10-24 13:03:46 -0500417 * @brief Create a UserData section containing the AdditionalData
418 * contents as a JSON string.
419 *
420 * @param[in] ad - The AdditionalData contents
421 *
422 * @return std::unique_ptr<UserData> - The section
423 */
424std::unique_ptr<UserData> makeADUserDataSection(const AdditionalData& ad);
425
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600426/**
427 * @brief Create a UserData section containing various useful pieces
428 * of system information as a JSON string.
429 *
430 * @param[in] ad - The AdditionalData contents
431 * @param[in] dataIface - The data interface object
432 *
433 * @return std::unique_ptr<UserData> - The section
434 */
435std::unique_ptr<UserData>
436 makeSysInfoUserDataSection(const AdditionalData& ad,
437 const DataInterfaceBase& dataIface);
Matt Spinler56ad2a02020-03-26 14:00:52 -0500438
439/**
Matt Spinler5a90a952020-08-27 09:39:03 -0500440 * @brief Reads data from an opened file descriptor.
441 *
442 * @param[in] fd - The FD to read from
443 *
444 * @return std::vector<uint8_t> - The data read
445 */
446std::vector<uint8_t> readFD(int fd);
447
448/**
Matt Spinler56ad2a02020-03-26 14:00:52 -0500449 * @brief Create a UserData section that contains the data in the file
450 * pointed to by the file descriptor passed in.
451 *
452 * @param[in] componentID - The component ID of the PEL creator
453 * @param[in] file - The FFDC file information
454 */
455std::unique_ptr<UserData> makeFFDCuserDataSection(uint16_t componentID,
456 const PelFFDCfile& file);
Matt Spinlerafa857c2019-10-24 13:03:46 -0500457} // namespace util
458
Matt Spinlercb6b0592019-07-16 15:58:51 -0500459} // namespace pels
460} // namespace openpower