blob: 1f0ab678429a1206a2be090859e6ecd0a632d15f [file] [log] [blame]
Matt Spinler711d51d2019-11-06 09:36:51 -06001/**
2 * Copyright © 2019 IBM Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Jayanth Othayothda9b5832021-11-05 04:19:43 -050016#include "config.h"
17
Matt Spinlercb6b0592019-07-16 15:58:51 -050018#include "pel.hpp"
19
20#include "bcd_time.hpp"
Matt Spinler386a61e2020-08-13 15:51:12 -050021#include "extended_user_data.hpp"
Matt Spinlerc63e2e82019-12-02 15:50:12 -060022#include "extended_user_header.hpp"
Matt Spinleraa659472019-10-23 09:26:48 -050023#include "failing_mtms.hpp"
Andrew Geisslerf8e750d2022-01-14 14:56:13 -060024#include "fru_identity.hpp"
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +080025#include "json_utils.hpp"
Matt Spinlercb6b0592019-07-16 15:58:51 -050026#include "log_id.hpp"
Matt Spinlerf1e85e22019-11-01 11:31:31 -050027#include "pel_rules.hpp"
Aatir186ce8c2019-10-20 15:13:39 -050028#include "pel_values.hpp"
Matt Spinler131870c2019-09-25 13:29:04 -050029#include "section_factory.hpp"
Matt Spinlerbd716f02019-10-15 10:54:11 -050030#include "src.hpp"
Matt Spinlercb6b0592019-07-16 15:58:51 -050031#include "stream.hpp"
Matt Spinlerafa857c2019-10-24 13:03:46 -050032#include "user_data_formats.hpp"
Matt Spinlercb6b0592019-07-16 15:58:51 -050033
Jayanth Othayoth92b20662021-11-05 00:09:15 -050034#ifdef PEL_ENABLE_PHAL
Jayanth Othayothda9b5832021-11-05 04:19:43 -050035#include "phal_service_actions.hpp"
Jayanth Othayothe8bdeea2021-06-03 03:01:16 -050036#include "sbe_ffdc_handler.hpp"
37#endif
38
Matt Spinler5b289b22020-03-26 14:27:19 -050039#include <sys/stat.h>
40#include <unistd.h>
41
Matt Spinlerfd2da662023-07-07 16:25:14 -050042#include <phosphor-logging/lg2.hpp>
Matt Spinler07eefc52019-09-26 11:18:26 -050043
Jayanth Othayoth1aa90d42023-09-13 04:25:45 -050044#include <format>
Patrick Williams2544b412022-10-04 08:41:06 -050045#include <iostream>
46
Matt Spinlercb6b0592019-07-16 15:58:51 -050047namespace openpower
48{
49namespace pels
50{
Aatir186ce8c2019-10-20 15:13:39 -050051namespace pv = openpower::pels::pel_values;
Matt Spinlerb8323632019-09-20 15:11:04 -050052
Matt Spinler677381b2020-01-23 10:04:29 -060053constexpr auto unknownValue = "Unknown";
54
Matt Spinler4bfc9082020-03-24 15:05:54 -050055PEL::PEL(const message::Entry& regEntry, uint32_t obmcLogID, uint64_t timestamp,
Matt Spinlerbd716f02019-10-15 10:54:11 -050056 phosphor::logging::Entry::Level severity,
Jayanth Othayothe8bdeea2021-06-03 03:01:16 -050057 const AdditionalData& additionalData, const PelFFDC& ffdcFilesIn,
Matt Spinler9d921092022-12-15 11:54:49 -060058 const DataInterfaceBase& dataIface, const JournalBase& journal)
Matt Spinlerb8323632019-09-20 15:11:04 -050059{
Jayanth Othayothe8bdeea2021-06-03 03:01:16 -050060 // No changes in input, for non SBE error related requests
61 PelFFDC ffdcFiles = ffdcFilesIn;
62
Jayanth Othayoth92b20662021-11-05 00:09:15 -050063#ifdef PEL_ENABLE_PHAL
Jayanth Othayothe8bdeea2021-06-03 03:01:16 -050064 // Add sbe ffdc processed data into ffdcfiles.
65 namespace sbe = openpower::pels::sbe;
Patrick Williamsac1ba3f2023-05-10 07:50:16 -050066 auto processReq = std::any_of(ffdcFiles.begin(), ffdcFiles.end(),
67 [](const auto& file) {
68 return file.format == UserDataFormat::custom &&
69 file.subType == sbe::sbeFFDCSubType;
70 });
Jayanth Othayothe8bdeea2021-06-03 03:01:16 -050071 // sbeFFDC can't be destroyed until the end of the PEL constructor
72 // because it needs to keep around the FFDC Files to be used below.
73 std::unique_ptr<sbe::SbeFFDC> sbeFFDCPtr;
74 if (processReq)
75 {
Patrick Williams2544b412022-10-04 08:41:06 -050076 sbeFFDCPtr = std::make_unique<sbe::SbeFFDC>(additionalData,
77 ffdcFilesIn);
Jayanth Othayothe8bdeea2021-06-03 03:01:16 -050078 const auto& sbeFFDCFiles = sbeFFDCPtr->getSbeFFDC();
79 ffdcFiles.insert(ffdcFiles.end(), sbeFFDCFiles.begin(),
80 sbeFFDCFiles.end());
Jayanth Othayoth742b00b2022-06-30 05:16:57 -050081
82 // update pel priority for spare clock failures
83 if (auto customSeverity = sbeFFDCPtr->getSeverity())
84 {
85 severity = customSeverity.value();
86 }
Jayanth Othayothe8bdeea2021-06-03 03:01:16 -050087 }
88#endif
89
Matt Spinler85f61a62020-06-03 16:28:55 -050090 std::map<std::string, std::vector<std::string>> debugData;
Matt Spinler5a90a952020-08-27 09:39:03 -050091 nlohmann::json callouts;
Matt Spinler85f61a62020-06-03 16:28:55 -050092
Matt Spinler4bfc9082020-03-24 15:05:54 -050093 _ph = std::make_unique<PrivateHeader>(regEntry.componentID, obmcLogID,
Matt Spinlerb8323632019-09-20 15:11:04 -050094 timestamp);
Vijay Lobo6b3f3452021-04-15 23:04:42 -050095 _uh = std::make_unique<UserHeader>(regEntry, severity, additionalData,
96 dataIface);
Matt Spinlerb8323632019-09-20 15:11:04 -050097
Matt Spinler5a90a952020-08-27 09:39:03 -050098 // Extract any callouts embedded in an FFDC file.
99 if (!ffdcFiles.empty())
100 {
101 try
102 {
103 callouts = getCalloutJSON(ffdcFiles);
104 }
105 catch (const std::exception& e)
106 {
107 debugData.emplace("FFDC file JSON callouts error",
108 std::vector<std::string>{e.what()});
109 }
110 }
111
Patrick Williams2544b412022-10-04 08:41:06 -0500112 auto src = std::make_unique<SRC>(regEntry, additionalData, callouts,
113 dataIface);
Matt Spinler5a90a952020-08-27 09:39:03 -0500114
Matt Spinler85f61a62020-06-03 16:28:55 -0500115 if (!src->getDebugData().empty())
116 {
117 // Something didn't go as planned
118 debugData.emplace("SRC", src->getDebugData());
119 }
Matt Spinlerc63e2e82019-12-02 15:50:12 -0600120
Matt Spinler4bfc9082020-03-24 15:05:54 -0500121 auto euh = std::make_unique<ExtendedUserHeader>(dataIface, regEntry, *src);
Matt Spinlerc63e2e82019-12-02 15:50:12 -0600122
Matt Spinlerbd716f02019-10-15 10:54:11 -0500123 _optionalSections.push_back(std::move(src));
Matt Spinlerc63e2e82019-12-02 15:50:12 -0600124 _optionalSections.push_back(std::move(euh));
Matt Spinlerb8323632019-09-20 15:11:04 -0500125
Matt Spinleraa659472019-10-23 09:26:48 -0500126 auto mtms = std::make_unique<FailingMTMS>(dataIface);
127 _optionalSections.push_back(std::move(mtms));
Matt Spinlerbd716f02019-10-15 10:54:11 -0500128
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600129 auto ud = util::makeSysInfoUserDataSection(additionalData, dataIface);
Matt Spinler85f61a62020-06-03 16:28:55 -0500130 addUserDataSection(std::move(ud));
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600131
Sumit Kumar3e274432021-09-14 06:37:56 -0500132 // Check for pel severity of type - 0x51 = critical error, system
133 // termination and update terminate bit in SRC for pels
134 updateTerminateBitInSRCSection();
135
Matt Spinler9b7e94f2020-03-24 15:44:41 -0500136 // Create a UserData section from AdditionalData.
Matt Spinlerafa857c2019-10-24 13:03:46 -0500137 if (!additionalData.empty())
138 {
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600139 ud = util::makeADUserDataSection(additionalData);
Matt Spinler85f61a62020-06-03 16:28:55 -0500140 addUserDataSection(std::move(ud));
Matt Spinlerafa857c2019-10-24 13:03:46 -0500141 }
142
Matt Spinler56ad2a02020-03-26 14:00:52 -0500143 // Add any FFDC files into UserData sections
144 for (const auto& file : ffdcFiles)
145 {
146 ud = util::makeFFDCuserDataSection(regEntry.componentID, file);
147 if (!ud)
148 {
Matt Spinler85f61a62020-06-03 16:28:55 -0500149 // Add this error into the debug data UserData section
150 std::ostringstream msg;
151 msg << "Could not make PEL FFDC UserData section from file"
152 << std::hex << regEntry.componentID << " " << file.subType
153 << " " << file.version;
154 if (debugData.count("FFDC File"))
155 {
156 debugData.at("FFDC File").push_back(msg.str());
157 }
158 else
159 {
160 debugData.emplace("FFDC File",
161 std::vector<std::string>{msg.str()});
162 }
163
Matt Spinler56ad2a02020-03-26 14:00:52 -0500164 continue;
165 }
166
Matt Spinler85f61a62020-06-03 16:28:55 -0500167 addUserDataSection(std::move(ud));
168 }
Matt Spinler56ad2a02020-03-26 14:00:52 -0500169
Jayanth Othayothda9b5832021-11-05 04:19:43 -0500170#ifdef PEL_ENABLE_PHAL
171 auto path = std::string(OBJ_ENTRY) + '/' + std::to_string(obmcLogID);
Jayanth Othayoth3ef7b602021-11-09 06:40:38 -0600172 openpower::pels::phal::createServiceActions(callouts, path, dataIface,
173 plid());
Jayanth Othayothda9b5832021-11-05 04:19:43 -0500174#endif
175
Matt Spinler85f61a62020-06-03 16:28:55 -0500176 // Store in the PEL any important debug data created while
177 // building the PEL sections.
178 if (!debugData.empty())
179 {
180 nlohmann::json data;
181 data["PEL Internal Debug Data"] = debugData;
182 ud = util::makeJSONUserDataSection(data);
183
184 addUserDataSection(std::move(ud));
185
186 // Also put in the journal for debug
Matt Spinler45796e82022-07-01 11:25:27 -0500187 for (const auto& [name, msgs] : debugData)
Matt Spinler85f61a62020-06-03 16:28:55 -0500188 {
Matt Spinler45796e82022-07-01 11:25:27 -0500189 for (const auto& message : msgs)
Matt Spinler85f61a62020-06-03 16:28:55 -0500190 {
Matt Spinlerfd2da662023-07-07 16:25:14 -0500191 lg2::info("{NAME}: {MSG}", "NAME", name, "MSG", message);
Matt Spinler56ad2a02020-03-26 14:00:52 -0500192 }
193 }
Matt Spinler56ad2a02020-03-26 14:00:52 -0500194 }
195
Matt Spinler9d921092022-12-15 11:54:49 -0600196 addJournalSections(regEntry, journal);
197
Matt Spinler97d19b42019-10-29 11:34:03 -0500198 _ph->setSectionCount(2 + _optionalSections.size());
Matt Spinlerf1e85e22019-11-01 11:31:31 -0500199
200 checkRulesAndFix();
Matt Spinlerb8323632019-09-20 15:11:04 -0500201}
Matt Spinlercb6b0592019-07-16 15:58:51 -0500202
Patrick Williams2544b412022-10-04 08:41:06 -0500203PEL::PEL(std::vector<uint8_t>& data) : PEL(data, 0) {}
Matt Spinlercb6b0592019-07-16 15:58:51 -0500204
Matt Spinler07eefc52019-09-26 11:18:26 -0500205PEL::PEL(std::vector<uint8_t>& data, uint32_t obmcLogID)
Matt Spinlercb6b0592019-07-16 15:58:51 -0500206{
Matt Spinler07eefc52019-09-26 11:18:26 -0500207 populateFromRawData(data, obmcLogID);
Matt Spinlercb6b0592019-07-16 15:58:51 -0500208}
209
Matt Spinler07eefc52019-09-26 11:18:26 -0500210void PEL::populateFromRawData(std::vector<uint8_t>& data, uint32_t obmcLogID)
Matt Spinlercb6b0592019-07-16 15:58:51 -0500211{
Matt Spinler07eefc52019-09-26 11:18:26 -0500212 Stream pelData{data};
Matt Spinlercb6b0592019-07-16 15:58:51 -0500213 _ph = std::make_unique<PrivateHeader>(pelData);
214 if (obmcLogID != 0)
215 {
Matt Spinler97d19b42019-10-29 11:34:03 -0500216 _ph->setOBMCLogID(obmcLogID);
Matt Spinlercb6b0592019-07-16 15:58:51 -0500217 }
218
219 _uh = std::make_unique<UserHeader>(pelData);
Matt Spinler131870c2019-09-25 13:29:04 -0500220
221 // Use the section factory to create the rest of the objects
222 for (size_t i = 2; i < _ph->sectionCount(); i++)
223 {
224 auto section = section_factory::create(pelData);
225 _optionalSections.push_back(std::move(section));
226 }
Matt Spinlercb6b0592019-07-16 15:58:51 -0500227}
228
229bool PEL::valid() const
230{
231 bool valid = _ph->valid();
232
233 if (valid)
234 {
235 valid = _uh->valid();
236 }
237
Matt Spinler131870c2019-09-25 13:29:04 -0500238 if (valid)
239 {
240 if (!std::all_of(_optionalSections.begin(), _optionalSections.end(),
241 [](const auto& section) { return section->valid(); }))
242 {
243 valid = false;
244 }
245 }
246
Matt Spinlercb6b0592019-07-16 15:58:51 -0500247 return valid;
248}
249
250void PEL::setCommitTime()
251{
252 auto now = std::chrono::system_clock::now();
Matt Spinler97d19b42019-10-29 11:34:03 -0500253 _ph->setCommitTimestamp(getBCDTime(now));
Matt Spinlercb6b0592019-07-16 15:58:51 -0500254}
255
256void PEL::assignID()
257{
Matt Spinler97d19b42019-10-29 11:34:03 -0500258 _ph->setID(generatePELID());
Matt Spinlercb6b0592019-07-16 15:58:51 -0500259}
260
Matt Spinler06885452019-11-06 10:35:42 -0600261void PEL::flatten(std::vector<uint8_t>& pelBuffer) const
Matt Spinlercb6b0592019-07-16 15:58:51 -0500262{
263 Stream pelData{pelBuffer};
Matt Spinlerb8323632019-09-20 15:11:04 -0500264
Matt Spinler07eefc52019-09-26 11:18:26 -0500265 if (!valid())
Matt Spinlercb6b0592019-07-16 15:58:51 -0500266 {
Matt Spinlerfd2da662023-07-07 16:25:14 -0500267 lg2::warning("Unflattening an invalid PEL");
Matt Spinlercb6b0592019-07-16 15:58:51 -0500268 }
269
Matt Spinler07eefc52019-09-26 11:18:26 -0500270 _ph->flatten(pelData);
Matt Spinlerb8323632019-09-20 15:11:04 -0500271 _uh->flatten(pelData);
Matt Spinler07eefc52019-09-26 11:18:26 -0500272
273 for (auto& section : _optionalSections)
274 {
275 section->flatten(pelData);
276 }
Matt Spinlercb6b0592019-07-16 15:58:51 -0500277}
278
Matt Spinler06885452019-11-06 10:35:42 -0600279std::vector<uint8_t> PEL::data() const
Matt Spinlercb6b0592019-07-16 15:58:51 -0500280{
Matt Spinler07eefc52019-09-26 11:18:26 -0500281 std::vector<uint8_t> pelData;
282 flatten(pelData);
283 return pelData;
Matt Spinlercb6b0592019-07-16 15:58:51 -0500284}
285
Matt Spinlerf1b46ff2020-01-22 14:10:04 -0600286size_t PEL::size() const
287{
288 size_t size = 0;
289
290 if (_ph)
291 {
292 size += _ph->header().size;
293 }
294
295 if (_uh)
296 {
297 size += _uh->header().size;
298 }
299
300 for (const auto& section : _optionalSections)
301 {
302 size += section->header().size;
303 }
304
305 return size;
306}
307
Matt Spinlerbd716f02019-10-15 10:54:11 -0500308std::optional<SRC*> PEL::primarySRC() const
309{
Patrick Williamsac1ba3f2023-05-10 07:50:16 -0500310 auto src = std::find_if(_optionalSections.begin(), _optionalSections.end(),
311 [](auto& section) {
312 return section->header().id ==
313 static_cast<uint16_t>(SectionID::primarySRC);
314 });
Matt Spinlerbd716f02019-10-15 10:54:11 -0500315 if (src != _optionalSections.end())
316 {
317 return static_cast<SRC*>(src->get());
318 }
319
320 return std::nullopt;
321}
322
Matt Spinlerf1e85e22019-11-01 11:31:31 -0500323void PEL::checkRulesAndFix()
324{
Matt Spinler1f93c592020-09-10 10:43:08 -0500325 // Only fix if the action flags are at their default value which
326 // means they weren't specified in the registry. Otherwise
327 // assume the user knows what they are doing.
328 if (_uh->actionFlags() == actionFlagsDefault)
329 {
Patrick Williams2544b412022-10-04 08:41:06 -0500330 auto [actionFlags, eventType] = pel_rules::check(0, _uh->eventType(),
331 _uh->severity());
Matt Spinlerf1e85e22019-11-01 11:31:31 -0500332
Matt Spinler1f93c592020-09-10 10:43:08 -0500333 _uh->setActionFlags(actionFlags);
334 _uh->setEventType(eventType);
335 }
Matt Spinlerf1e85e22019-11-01 11:31:31 -0500336}
337
Matt Spinleracb7c102020-01-10 13:49:22 -0600338void PEL::printSectionInJSON(const Section& section, std::string& buf,
Harisuddin Mohamed Isaa214ed32020-02-28 15:58:23 +0800339 std::map<uint16_t, size_t>& pluralSections,
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800340 message::Registry& registry,
341 const std::vector<std::string>& plugins,
342 uint8_t creatorID) const
Aatir186ce8c2019-10-20 15:13:39 -0500343{
344 char tmpB[5];
Aatir Manzurad0e0472019-10-07 13:18:37 -0500345 uint8_t id[] = {static_cast<uint8_t>(section.header().id >> 8),
346 static_cast<uint8_t>(section.header().id)};
347 sprintf(tmpB, "%c%c", id[0], id[1]);
348 std::string sectionID(tmpB);
349 std::string sectionName = pv::sectionTitles.count(sectionID)
350 ? pv::sectionTitles.at(sectionID)
351 : "Unknown Section";
Matt Spinleracb7c102020-01-10 13:49:22 -0600352
353 // Add a count if there are multiple of this type of section
354 auto count = pluralSections.find(section.header().id);
355 if (count != pluralSections.end())
356 {
357 sectionName += " " + std::to_string(count->second);
358 count->second++;
359 }
360
Aatir186ce8c2019-10-20 15:13:39 -0500361 if (section.valid())
362 {
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800363 std::optional<std::string> json;
364 if (sectionID == "PS" || sectionID == "SS")
365 {
Harisuddin Mohamed Isac8d6cc62020-08-19 22:47:19 +0800366 json = section.getJSON(registry, plugins, creatorID);
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800367 }
Matt Spinler386a61e2020-08-13 15:51:12 -0500368 else if ((sectionID == "UD") || (sectionID == "ED"))
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800369 {
Harisuddin Mohamed Isa3fdcd4e2020-08-26 11:56:42 +0800370 json = section.getJSON(creatorID, plugins);
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800371 }
372 else
373 {
Matt Spinlerb832aa52023-03-21 15:32:34 -0500374 json = section.getJSON(creatorID);
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800375 }
Matt Spinler4220a152020-03-26 10:18:09 -0500376
377 buf += "\"" + sectionName + "\": {\n";
378
Aatir Manzurad0e0472019-10-07 13:18:37 -0500379 if (json)
380 {
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800381 buf += *json + "\n},\n";
Aatir Manzurad0e0472019-10-07 13:18:37 -0500382 }
383 else
384 {
Matt Spinler4220a152020-03-26 10:18:09 -0500385 jsonInsert(buf, pv::sectionVer,
386 getNumberString("%d", section.header().version), 1);
387 jsonInsert(buf, pv::subSection,
388 getNumberString("%d", section.header().subType), 1);
389 jsonInsert(buf, pv::createdBy,
390 getNumberString("0x%X", section.header().componentID),
391 1);
392
Aatir Manzurad0e0472019-10-07 13:18:37 -0500393 std::vector<uint8_t> data;
394 Stream s{data};
395 section.flatten(s);
Matt Spinler4220a152020-03-26 10:18:09 -0500396 std::string dstr =
397 dumpHex(std::data(data) + SectionHeader::flattenedSize(),
Harisuddin Mohamed Isa097ad122020-06-11 21:19:41 +0800398 data.size() - SectionHeader::flattenedSize(), 2);
Matt Spinler4220a152020-03-26 10:18:09 -0500399 std::string jsonIndent(indentLevel, 0x20);
400 buf += jsonIndent + "\"Data\": [\n";
401 buf += dstr;
402 buf += jsonIndent + "]\n";
403 buf += "},\n";
Aatir Manzurad0e0472019-10-07 13:18:37 -0500404 }
Aatir186ce8c2019-10-20 15:13:39 -0500405 }
406 else
407 {
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800408 buf += "\n\"Invalid Section\": [\n \"invalid\"\n],\n";
Aatir186ce8c2019-10-20 15:13:39 -0500409 }
410}
411
Matt Spinleracb7c102020-01-10 13:49:22 -0600412std::map<uint16_t, size_t> PEL::getPluralSections() const
413{
414 std::map<uint16_t, size_t> sectionCounts;
415
416 for (const auto& section : optionalSections())
417 {
418 if (sectionCounts.find(section->header().id) == sectionCounts.end())
419 {
420 sectionCounts[section->header().id] = 1;
421 }
422 else
423 {
424 sectionCounts[section->header().id]++;
425 }
426 }
427
428 std::map<uint16_t, size_t> sections;
429 for (const auto& [id, count] : sectionCounts)
430 {
431 if (count > 1)
432 {
433 // Start with 0 here and printSectionInJSON()
434 // will increment it as it goes.
435 sections.emplace(id, 0);
436 }
437 }
438
439 return sections;
440}
441
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800442void PEL::toJSON(message::Registry& registry,
443 const std::vector<std::string>& plugins) const
Aatir186ce8c2019-10-20 15:13:39 -0500444{
Matt Spinleracb7c102020-01-10 13:49:22 -0600445 auto sections = getPluralSections();
446
Harisuddin Mohamed Isaa214ed32020-02-28 15:58:23 +0800447 std::string buf = "{\n";
Matt Spinlerb832aa52023-03-21 15:32:34 -0500448 printSectionInJSON(*(_ph.get()), buf, sections, registry, plugins,
449 _ph->creatorID());
450 printSectionInJSON(*(_uh.get()), buf, sections, registry, plugins,
451 _ph->creatorID());
Aatir186ce8c2019-10-20 15:13:39 -0500452 for (auto& section : this->optionalSections())
453 {
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800454 printSectionInJSON(*(section.get()), buf, sections, registry, plugins,
455 _ph->creatorID());
Aatir186ce8c2019-10-20 15:13:39 -0500456 }
457 buf += "}";
458 std::size_t found = buf.rfind(",");
459 if (found != std::string::npos)
460 buf.replace(found, 1, "");
461 std::cout << buf << std::endl;
462}
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800463
Matt Spinler85f61a62020-06-03 16:28:55 -0500464bool PEL::addUserDataSection(std::unique_ptr<UserData> userData)
465{
466 if (size() + userData->header().size > _maxPELSize)
467 {
468 if (userData->shrink(_maxPELSize - size()))
469 {
470 _optionalSections.push_back(std::move(userData));
471 }
472 else
473 {
Matt Spinlerfd2da662023-07-07 16:25:14 -0500474 lg2::warning("Could not shrink UserData section. Dropping. "
475 "Section size = {SSIZE}, Component ID = {COMP_ID}, "
476 "Subtype = {SUBTYPE}, Version = {VERSION}",
477 "SSIZE", userData->header().size, "COMP_ID",
478 userData->header().componentID, "SUBTYPE",
479 userData->header().subType, "VERSION",
480 userData->header().version);
Matt Spinler85f61a62020-06-03 16:28:55 -0500481 return false;
482 }
483 }
484 else
485 {
486 _optionalSections.push_back(std::move(userData));
487 }
488 return true;
489}
490
Matt Spinler5a90a952020-08-27 09:39:03 -0500491nlohmann::json PEL::getCalloutJSON(const PelFFDC& ffdcFiles)
492{
493 nlohmann::json callouts;
494
495 for (const auto& file : ffdcFiles)
496 {
497 if ((file.format == UserDataFormat::json) &&
498 (file.subType == jsonCalloutSubtype))
499 {
500 auto data = util::readFD(file.fd);
501 if (data.empty())
502 {
503 throw std::runtime_error{
504 "Could not get data from JSON callout file descriptor"};
505 }
506
507 std::string jsonString{data.begin(), data.begin() + data.size()};
508
509 callouts = nlohmann::json::parse(jsonString);
510 break;
511 }
512 }
513
514 return callouts;
515}
516
Andrew Geisslerf8e750d2022-01-14 14:56:13 -0600517bool PEL::isHwCalloutPresent() const
Andrew Geissler44fc3162020-07-09 09:21:31 -0500518{
519 auto pSRC = primarySRC();
520 if (!pSRC)
521 {
522 return false;
523 }
524
525 bool calloutPresent = false;
526 if ((*pSRC)->callouts())
527 {
528 for (auto& i : (*pSRC)->callouts()->callouts())
529 {
530 if (((*i).fruIdentity()))
531 {
532 auto& fruId = (*i).fruIdentity();
Andrew Geisslerf8e750d2022-01-14 14:56:13 -0600533 if ((*fruId).failingComponentType() ==
534 src::FRUIdentity::hardwareFRU)
Andrew Geissler44fc3162020-07-09 09:21:31 -0500535 {
536 calloutPresent = true;
537 break;
538 }
539 }
540 }
541 }
542
543 return calloutPresent;
544}
545
Sumit Kumar3160a542021-04-26 08:07:04 -0500546void PEL::updateSysInfoInExtendedUserDataSection(
547 const DataInterfaceBase& dataIface)
548{
549 const AdditionalData additionalData;
550
551 // Check for PEL from Hostboot
552 if (_ph->creatorID() == static_cast<uint8_t>(CreatorID::hostboot))
553 {
554 // Get the ED section from PEL
555 auto op = std::find_if(_optionalSections.begin(),
Patrick Williams5fb575a2023-10-20 11:18:21 -0500556 _optionalSections.end(), [](auto& section) {
Patrick Williamsac1ba3f2023-05-10 07:50:16 -0500557 return section->header().id ==
558 static_cast<uint16_t>(SectionID::extUserData);
559 });
Sumit Kumar3160a542021-04-26 08:07:04 -0500560
561 // Check for ED section found and its not the last section of PEL
562 if (op != _optionalSections.end())
563 {
564 // Get the extended user data class mapped to found section
565 auto extUserData = static_cast<ExtendedUserData*>(op->get());
566
567 // Check for the creator ID is for OpenBMC
568 if (extUserData->creatorID() ==
569 static_cast<uint8_t>(CreatorID::openBMC))
570 {
571 // Update subtype and component id
572 auto subType = static_cast<uint8_t>(UserDataFormat::json);
573 auto componentId =
574 static_cast<uint16_t>(ComponentID::phosphorLogging);
575
576 // Update system data to ED section
George Liu9ac0d9b2022-07-15 10:57:38 +0800577 auto ud = util::makeSysInfoUserDataSection(additionalData,
578 dataIface, false);
Sumit Kumar3160a542021-04-26 08:07:04 -0500579 extUserData->updateDataSection(subType, componentId,
580 ud->data());
581 }
582 }
583 }
584}
585
Matt Spinler8e65f4e2023-05-02 13:40:08 -0500586bool PEL::getDeconfigFlag() const
587{
588 auto creator = static_cast<CreatorID>(_ph->creatorID());
589
590 if ((creator == CreatorID::openBMC) || (creator == CreatorID::hostboot))
591 {
592 auto src = primarySRC();
593 return (*src)->getErrorStatusFlag(SRC::ErrorStatusFlags::deconfigured);
594 }
595 return false;
596}
597
598bool PEL::getGuardFlag() const
599{
600 auto creator = static_cast<CreatorID>(_ph->creatorID());
601
602 if ((creator == CreatorID::openBMC) || (creator == CreatorID::hostboot))
603 {
604 auto src = primarySRC();
605 return (*src)->getErrorStatusFlag(SRC::ErrorStatusFlags::guarded);
606 }
607 return false;
608}
609
Sumit Kumar3e274432021-09-14 06:37:56 -0500610void PEL::updateTerminateBitInSRCSection()
611{
612 // Check for pel severity of type - 0x51 = critical error, system
613 // termination
614 if (_uh->severity() == 0x51)
615 {
616 // Get the primary SRC section
617 auto pSRC = primarySRC();
618 if (pSRC)
619 {
620 (*pSRC)->setTerminateBit();
621 }
622 }
623}
624
Matt Spinler9d921092022-12-15 11:54:49 -0600625void PEL::addJournalSections(const message::Entry& regEntry,
626 const JournalBase& journal)
627{
628 if (!regEntry.journalCapture)
629 {
630 return;
631 }
632
633 // Write all unwritten journal data to disk.
634 journal.sync();
635
636 const auto& jc = regEntry.journalCapture.value();
637 std::vector<std::vector<std::string>> allMessages;
638
639 if (std::holds_alternative<size_t>(jc))
640 {
641 // Get the previous numLines journal entries
642 const auto& numLines = std::get<size_t>(jc);
643 try
644 {
645 auto messages = journal.getMessages("", numLines);
646 if (!messages.empty())
647 {
648 allMessages.push_back(std::move(messages));
649 }
650 }
651 catch (const std::exception& e)
652 {
Matt Spinlerfd2da662023-07-07 16:25:14 -0500653 lg2::error("Failed during journal collection: {ERROR}", "ERROR", e);
Matt Spinler9d921092022-12-15 11:54:49 -0600654 }
655 }
656 else if (std::holds_alternative<message::AppCaptureList>(jc))
657 {
658 // Get journal entries based on the syslog id field.
659 const auto& sections = std::get<message::AppCaptureList>(jc);
660 for (const auto& [syslogID, numLines] : sections)
661 {
662 try
663 {
664 auto messages = journal.getMessages(syslogID, numLines);
665 if (!messages.empty())
666 {
667 allMessages.push_back(std::move(messages));
668 }
669 }
670 catch (const std::exception& e)
671 {
Matt Spinlerfd2da662023-07-07 16:25:14 -0500672 lg2::error("Failed during journal collection: {ERROR}", "ERROR",
673 e);
Matt Spinler9d921092022-12-15 11:54:49 -0600674 }
675 }
676 }
677
678 // Create the UserData sections
679 for (const auto& messages : allMessages)
680 {
681 auto buffer = util::flattenLines(messages);
682
683 // If the buffer is way too big, it can overflow the uint16_t
684 // PEL section size field that is checked below so do a cursory
685 // check here.
686 if (buffer.size() > _maxPELSize)
687 {
Matt Spinlerfd2da662023-07-07 16:25:14 -0500688 lg2::warning(
689 "Journal UserData section does not fit in PEL, dropping. "
690 "PEL size = {PEL_SIZE}, data size = {DATA_SIZE}",
691 "PEL_SIZE", size(), "DATA_SIZE", buffer.size());
Matt Spinler9d921092022-12-15 11:54:49 -0600692 continue;
693 }
694
695 // Sections must be 4 byte aligned.
696 while (buffer.size() % 4 != 0)
697 {
698 buffer.push_back(0);
699 }
700
701 auto ud = std::make_unique<UserData>(
702 static_cast<uint16_t>(ComponentID::phosphorLogging),
703 static_cast<uint8_t>(UserDataFormat::text),
704 static_cast<uint8_t>(UserDataFormatVersion::text), buffer);
705
706 if (size() + ud->header().size <= _maxPELSize)
707 {
708 _optionalSections.push_back(std::move(ud));
709 }
710 else
711 {
712 // Don't attempt to shrink here since we'd be dropping the
713 // most recent journal entries which would be confusing.
Matt Spinlerfd2da662023-07-07 16:25:14 -0500714 lg2::warning(
715 "Journal UserData section does not fit in PEL, dropping. "
716 "PEL size = {PEL_SIZE}, data size = {DATA_SIZE}",
717 "PEL_SIZE", size(), "DATA_SIZE", buffer.size());
Matt Spinler9d921092022-12-15 11:54:49 -0600718 ud.reset();
719 continue;
720 }
721 }
722}
723
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600724namespace util
725{
726
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600727std::unique_ptr<UserData> makeJSONUserDataSection(const nlohmann::json& json)
728{
729 auto jsonString = json.dump();
730 std::vector<uint8_t> jsonData(jsonString.begin(), jsonString.end());
731
732 // Pad to a 4 byte boundary
733 while ((jsonData.size() % 4) != 0)
734 {
735 jsonData.push_back(0);
736 }
737
738 return std::make_unique<UserData>(
739 static_cast<uint16_t>(ComponentID::phosphorLogging),
740 static_cast<uint8_t>(UserDataFormat::json),
741 static_cast<uint8_t>(UserDataFormatVersion::json), jsonData);
742}
743
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600744std::unique_ptr<UserData> makeADUserDataSection(const AdditionalData& ad)
745{
746 assert(!ad.empty());
747 nlohmann::json json;
748
749 // Remove the 'ESEL' entry, as it contains a full PEL in the value.
750 if (ad.getValue("ESEL"))
751 {
752 auto newAD = ad;
753 newAD.remove("ESEL");
754 json = newAD.toJSON();
755 }
756 else
757 {
758 json = ad.toJSON();
759 }
760
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600761 return makeJSONUserDataSection(json);
762}
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600763
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600764void addProcessNameToJSON(nlohmann::json& json,
765 const std::optional<std::string>& pid,
766 const DataInterfaceBase& dataIface)
767{
Matt Spinler677381b2020-01-23 10:04:29 -0600768 std::string name{unknownValue};
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600769
770 try
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600771 {
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600772 if (pid)
773 {
774 auto n = dataIface.getProcessName(*pid);
775 if (n)
776 {
777 name = *n;
778 }
779 }
780 }
Patrick Williams66491c62021-10-06 12:23:37 -0500781 catch (const std::exception& e)
Patrick Williams2544b412022-10-04 08:41:06 -0500782 {}
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600783
Sumit Kumar3160a542021-04-26 08:07:04 -0500784 if (pid)
785 {
786 json["Process Name"] = std::move(name);
787 }
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600788}
789
Matt Spinler677381b2020-01-23 10:04:29 -0600790void addBMCFWVersionIDToJSON(nlohmann::json& json,
791 const DataInterfaceBase& dataIface)
792{
793 auto id = dataIface.getBMCFWVersionID();
794 if (id.empty())
795 {
796 id = unknownValue;
797 }
798
Matt Spinlerc2b8a512021-05-21 12:44:42 -0600799 json["FW Version ID"] = std::move(id);
Matt Spinler677381b2020-01-23 10:04:29 -0600800}
801
Matt Spinler4aa23a12020-02-03 15:05:09 -0600802std::string lastSegment(char separator, std::string data)
803{
804 auto pos = data.find_last_of(separator);
805 if (pos != std::string::npos)
806 {
807 data = data.substr(pos + 1);
808 }
809
810 return data;
811}
812
Ben Tynere32b7e72021-05-18 12:38:40 -0500813void addIMKeyword(nlohmann::json& json, const DataInterfaceBase& dataIface)
814{
815 auto keyword = dataIface.getSystemIMKeyword();
816
817 std::string value{};
818
819 std::for_each(keyword.begin(), keyword.end(), [&](const auto& byte) {
Jayanth Othayoth1aa90d42023-09-13 04:25:45 -0500820 value += std::format("{:02X}", byte);
Ben Tynere32b7e72021-05-18 12:38:40 -0500821 });
822
823 json["System IM"] = value;
824}
825
Matt Spinler4aa23a12020-02-03 15:05:09 -0600826void addStatesToJSON(nlohmann::json& json, const DataInterfaceBase& dataIface)
827{
828 json["BMCState"] = lastSegment('.', dataIface.getBMCState());
829 json["ChassisState"] = lastSegment('.', dataIface.getChassisState());
830 json["HostState"] = lastSegment('.', dataIface.getHostState());
Sumit Kumar2c36fdd2021-09-21 03:12:11 -0500831 json["BootState"] = lastSegment('.', dataIface.getBootState());
Matt Spinler4aa23a12020-02-03 15:05:09 -0600832}
833
George Liu9ac0d9b2022-07-15 10:57:38 +0800834void addBMCUptime(nlohmann::json& json, const DataInterfaceBase& dataIface)
835{
836 auto seconds = dataIface.getUptimeInSeconds();
837 if (seconds)
838 {
839 json["BMCUptime"] = dataIface.getBMCUptime(*seconds);
840 }
841 else
842 {
843 json["BMCUptime"] = "";
844 }
845 json["BMCLoad"] = dataIface.getBMCLoadAvg();
846}
847
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600848std::unique_ptr<UserData>
849 makeSysInfoUserDataSection(const AdditionalData& ad,
George Liu9ac0d9b2022-07-15 10:57:38 +0800850 const DataInterfaceBase& dataIface,
851 bool addUptime)
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600852{
853 nlohmann::json json;
854
855 addProcessNameToJSON(json, ad.getValue("_PID"), dataIface);
Matt Spinler677381b2020-01-23 10:04:29 -0600856 addBMCFWVersionIDToJSON(json, dataIface);
Ben Tynere32b7e72021-05-18 12:38:40 -0500857 addIMKeyword(json, dataIface);
Matt Spinler4aa23a12020-02-03 15:05:09 -0600858 addStatesToJSON(json, dataIface);
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600859
George Liu9ac0d9b2022-07-15 10:57:38 +0800860 if (addUptime)
861 {
862 addBMCUptime(json, dataIface);
863 }
864
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600865 return makeJSONUserDataSection(json);
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600866}
867
Matt Spinler5b289b22020-03-26 14:27:19 -0500868std::vector<uint8_t> readFD(int fd)
869{
870 std::vector<uint8_t> data;
871
872 // Get the size
873 struct stat s;
874 int r = fstat(fd, &s);
875 if (r != 0)
876 {
877 auto e = errno;
Matt Spinlerfd2da662023-07-07 16:25:14 -0500878 lg2::error("Could not get FFDC file size from FD, errno = {ERRNO}",
879 "ERRNO", e);
Matt Spinler5b289b22020-03-26 14:27:19 -0500880 return data;
881 }
882
883 if (0 == s.st_size)
884 {
Matt Spinlerfd2da662023-07-07 16:25:14 -0500885 lg2::error("FFDC file is empty");
Matt Spinler5b289b22020-03-26 14:27:19 -0500886 return data;
887 }
888
889 data.resize(s.st_size);
890
891 // Make sure its at the beginning, as maybe another
892 // extension already used it.
893 r = lseek(fd, 0, SEEK_SET);
894 if (r == -1)
895 {
896 auto e = errno;
Matt Spinlerfd2da662023-07-07 16:25:14 -0500897 lg2::error("Could not seek to beginning of FFDC file, errno = {ERRNO}",
898 "ERRNO", e);
Matt Spinler5b289b22020-03-26 14:27:19 -0500899 return data;
900 }
901
902 r = read(fd, data.data(), s.st_size);
903 if (r == -1)
904 {
905 auto e = errno;
Matt Spinlerfd2da662023-07-07 16:25:14 -0500906 lg2::error("Could not read FFDC file, errno = {ERRNO}", "ERRNO", e);
Matt Spinler5b289b22020-03-26 14:27:19 -0500907 }
908 else if (r != s.st_size)
909 {
Matt Spinlerfd2da662023-07-07 16:25:14 -0500910 lg2::warning("Could not read full FFDC file. "
911 "File size = {FSIZE}, Size read = {SIZE_READ}",
912 "FSIZE", s.st_size, "SIZE_READ", r);
Matt Spinler5b289b22020-03-26 14:27:19 -0500913 }
914
915 return data;
916}
917
Matt Spinler56ad2a02020-03-26 14:00:52 -0500918std::unique_ptr<UserData> makeFFDCuserDataSection(uint16_t componentID,
919 const PelFFDCfile& file)
920{
Matt Spinler5b289b22020-03-26 14:27:19 -0500921 auto data = readFD(file.fd);
922
923 if (data.empty())
924 {
925 return std::unique_ptr<UserData>();
926 }
927
928 // The data needs 4 Byte alignment, and save amount padded for the
929 // CBOR case.
930 uint32_t pad = 0;
931 while (data.size() % 4)
932 {
933 data.push_back(0);
934 pad++;
935 }
936
937 // For JSON, CBOR, and Text use our component ID, subType, and version,
938 // otherwise use the supplied ones.
939 uint16_t compID = static_cast<uint16_t>(ComponentID::phosphorLogging);
940 uint8_t subType{};
941 uint8_t version{};
942
943 switch (file.format)
944 {
945 case UserDataFormat::json:
946 subType = static_cast<uint8_t>(UserDataFormat::json);
947 version = static_cast<uint8_t>(UserDataFormatVersion::json);
948 break;
949 case UserDataFormat::cbor:
950 subType = static_cast<uint8_t>(UserDataFormat::cbor);
951 version = static_cast<uint8_t>(UserDataFormatVersion::cbor);
952
953 // The CBOR parser will fail on the extra pad bytes since they
954 // aren't CBOR. Add the amount we padded to the end and other
955 // code will remove it all before parsing.
956 {
957 data.resize(data.size() + 4);
958 Stream stream{data};
959 stream.offset(data.size() - 4);
960 stream << pad;
961 }
962
963 break;
964 case UserDataFormat::text:
965 subType = static_cast<uint8_t>(UserDataFormat::text);
966 version = static_cast<uint8_t>(UserDataFormatVersion::text);
967 break;
968 case UserDataFormat::custom:
969 default:
970 // Use the passed in values
971 compID = componentID;
972 subType = file.subType;
973 version = file.version;
974 break;
975 }
976
977 return std::make_unique<UserData>(compID, subType, version, data);
Matt Spinler56ad2a02020-03-26 14:00:52 -0500978}
979
Matt Spinler9d921092022-12-15 11:54:49 -0600980std::vector<uint8_t> flattenLines(const std::vector<std::string>& lines)
981{
982 std::vector<uint8_t> out;
983
984 for (const auto& line : lines)
985 {
986 out.insert(out.end(), line.begin(), line.end());
987
988 if (out.back() != '\n')
989 {
990 out.push_back('\n');
991 }
992 }
993
994 return out;
995}
996
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600997} // namespace util
998
Matt Spinlercb6b0592019-07-16 15:58:51 -0500999} // namespace pels
1000} // namespace openpower