blob: a6f0af343574e1e913aeb43489044d6eaa27cc28 [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"
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +080024#include "json_utils.hpp"
Matt Spinlercb6b0592019-07-16 15:58:51 -050025#include "log_id.hpp"
Matt Spinlerf1e85e22019-11-01 11:31:31 -050026#include "pel_rules.hpp"
Aatir186ce8c2019-10-20 15:13:39 -050027#include "pel_values.hpp"
Matt Spinler131870c2019-09-25 13:29:04 -050028#include "section_factory.hpp"
Matt Spinlerbd716f02019-10-15 10:54:11 -050029#include "src.hpp"
Matt Spinlercb6b0592019-07-16 15:58:51 -050030#include "stream.hpp"
Matt Spinlerafa857c2019-10-24 13:03:46 -050031#include "user_data_formats.hpp"
Matt Spinlercb6b0592019-07-16 15:58:51 -050032
Jayanth Othayoth92b20662021-11-05 00:09:15 -050033#ifdef PEL_ENABLE_PHAL
Jayanth Othayothda9b5832021-11-05 04:19:43 -050034#include "phal_service_actions.hpp"
Jayanth Othayothe8bdeea2021-06-03 03:01:16 -050035#include "sbe_ffdc_handler.hpp"
36#endif
37
Ben Tynere32b7e72021-05-18 12:38:40 -050038#include <fmt/format.h>
Matt Spinler5b289b22020-03-26 14:27:19 -050039#include <sys/stat.h>
40#include <unistd.h>
41
Aatir186ce8c2019-10-20 15:13:39 -050042#include <iostream>
Matt Spinler07eefc52019-09-26 11:18:26 -050043#include <phosphor-logging/log.hpp>
44
Matt Spinlercb6b0592019-07-16 15:58:51 -050045namespace openpower
46{
47namespace pels
48{
Matt Spinlerb8323632019-09-20 15:11:04 -050049namespace message = openpower::pels::message;
Aatir186ce8c2019-10-20 15:13:39 -050050namespace pv = openpower::pels::pel_values;
Matt Spinler4bfc9082020-03-24 15:05:54 -050051using namespace phosphor::logging;
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 Spinleraa659472019-10-23 09:26:48 -050058 const DataInterfaceBase& dataIface)
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;
66 auto processReq =
67 std::any_of(ffdcFiles.begin(), ffdcFiles.end(), [](const auto& file) {
68 return file.format == UserDataFormat::custom &&
69 file.subType == sbe::sbeFFDCSubType;
70 });
71 // 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 {
76 sbeFFDCPtr =
77 std::make_unique<sbe::SbeFFDC>(additionalData, ffdcFilesIn);
78 const auto& sbeFFDCFiles = sbeFFDCPtr->getSbeFFDC();
79 ffdcFiles.insert(ffdcFiles.end(), sbeFFDCFiles.begin(),
80 sbeFFDCFiles.end());
81 }
82#endif
83
Matt Spinler85f61a62020-06-03 16:28:55 -050084 std::map<std::string, std::vector<std::string>> debugData;
Matt Spinler5a90a952020-08-27 09:39:03 -050085 nlohmann::json callouts;
Matt Spinler85f61a62020-06-03 16:28:55 -050086
Matt Spinler4bfc9082020-03-24 15:05:54 -050087 _ph = std::make_unique<PrivateHeader>(regEntry.componentID, obmcLogID,
Matt Spinlerb8323632019-09-20 15:11:04 -050088 timestamp);
Vijay Lobo6b3f3452021-04-15 23:04:42 -050089 _uh = std::make_unique<UserHeader>(regEntry, severity, additionalData,
90 dataIface);
Matt Spinlerb8323632019-09-20 15:11:04 -050091
Matt Spinler5a90a952020-08-27 09:39:03 -050092 // Extract any callouts embedded in an FFDC file.
93 if (!ffdcFiles.empty())
94 {
95 try
96 {
97 callouts = getCalloutJSON(ffdcFiles);
98 }
99 catch (const std::exception& e)
100 {
101 debugData.emplace("FFDC file JSON callouts error",
102 std::vector<std::string>{e.what()});
103 }
104 }
105
106 auto src =
107 std::make_unique<SRC>(regEntry, additionalData, callouts, dataIface);
108
Matt Spinler85f61a62020-06-03 16:28:55 -0500109 if (!src->getDebugData().empty())
110 {
111 // Something didn't go as planned
112 debugData.emplace("SRC", src->getDebugData());
113 }
Matt Spinlerc63e2e82019-12-02 15:50:12 -0600114
Matt Spinler4bfc9082020-03-24 15:05:54 -0500115 auto euh = std::make_unique<ExtendedUserHeader>(dataIface, regEntry, *src);
Matt Spinlerc63e2e82019-12-02 15:50:12 -0600116
Matt Spinlerbd716f02019-10-15 10:54:11 -0500117 _optionalSections.push_back(std::move(src));
Matt Spinlerc63e2e82019-12-02 15:50:12 -0600118 _optionalSections.push_back(std::move(euh));
Matt Spinlerb8323632019-09-20 15:11:04 -0500119
Matt Spinleraa659472019-10-23 09:26:48 -0500120 auto mtms = std::make_unique<FailingMTMS>(dataIface);
121 _optionalSections.push_back(std::move(mtms));
Matt Spinlerbd716f02019-10-15 10:54:11 -0500122
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600123 auto ud = util::makeSysInfoUserDataSection(additionalData, dataIface);
Matt Spinler85f61a62020-06-03 16:28:55 -0500124 addUserDataSection(std::move(ud));
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600125
Sumit Kumar3e274432021-09-14 06:37:56 -0500126 // Check for pel severity of type - 0x51 = critical error, system
127 // termination and update terminate bit in SRC for pels
128 updateTerminateBitInSRCSection();
129
Matt Spinler9b7e94f2020-03-24 15:44:41 -0500130 // Create a UserData section from AdditionalData.
Matt Spinlerafa857c2019-10-24 13:03:46 -0500131 if (!additionalData.empty())
132 {
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600133 ud = util::makeADUserDataSection(additionalData);
Matt Spinler85f61a62020-06-03 16:28:55 -0500134 addUserDataSection(std::move(ud));
Matt Spinlerafa857c2019-10-24 13:03:46 -0500135 }
136
Matt Spinler56ad2a02020-03-26 14:00:52 -0500137 // Add any FFDC files into UserData sections
138 for (const auto& file : ffdcFiles)
139 {
140 ud = util::makeFFDCuserDataSection(regEntry.componentID, file);
141 if (!ud)
142 {
Matt Spinler85f61a62020-06-03 16:28:55 -0500143 // Add this error into the debug data UserData section
144 std::ostringstream msg;
145 msg << "Could not make PEL FFDC UserData section from file"
146 << std::hex << regEntry.componentID << " " << file.subType
147 << " " << file.version;
148 if (debugData.count("FFDC File"))
149 {
150 debugData.at("FFDC File").push_back(msg.str());
151 }
152 else
153 {
154 debugData.emplace("FFDC File",
155 std::vector<std::string>{msg.str()});
156 }
157
Matt Spinler56ad2a02020-03-26 14:00:52 -0500158 continue;
159 }
160
Matt Spinler85f61a62020-06-03 16:28:55 -0500161 addUserDataSection(std::move(ud));
162 }
Matt Spinler56ad2a02020-03-26 14:00:52 -0500163
Jayanth Othayothda9b5832021-11-05 04:19:43 -0500164#ifdef PEL_ENABLE_PHAL
165 auto path = std::string(OBJ_ENTRY) + '/' + std::to_string(obmcLogID);
Jayanth Othayoth3ef7b602021-11-09 06:40:38 -0600166 openpower::pels::phal::createServiceActions(callouts, path, dataIface,
167 plid());
Jayanth Othayothda9b5832021-11-05 04:19:43 -0500168#endif
169
Matt Spinler85f61a62020-06-03 16:28:55 -0500170 // Store in the PEL any important debug data created while
171 // building the PEL sections.
172 if (!debugData.empty())
173 {
174 nlohmann::json data;
175 data["PEL Internal Debug Data"] = debugData;
176 ud = util::makeJSONUserDataSection(data);
177
178 addUserDataSection(std::move(ud));
179
180 // Also put in the journal for debug
181 for (const auto& [name, data] : debugData)
182 {
183 for (const auto& message : data)
184 {
185 std::string entry = name + ": " + message;
186 log<level::INFO>(entry.c_str());
Matt Spinler56ad2a02020-03-26 14:00:52 -0500187 }
188 }
Matt Spinler56ad2a02020-03-26 14:00:52 -0500189 }
190
Matt Spinler97d19b42019-10-29 11:34:03 -0500191 _ph->setSectionCount(2 + _optionalSections.size());
Matt Spinlerf1e85e22019-11-01 11:31:31 -0500192
193 checkRulesAndFix();
Matt Spinlerb8323632019-09-20 15:11:04 -0500194}
Matt Spinlercb6b0592019-07-16 15:58:51 -0500195
Matt Spinler07eefc52019-09-26 11:18:26 -0500196PEL::PEL(std::vector<uint8_t>& data) : PEL(data, 0)
Matt Spinlercb6b0592019-07-16 15:58:51 -0500197{
198}
199
Matt Spinler07eefc52019-09-26 11:18:26 -0500200PEL::PEL(std::vector<uint8_t>& data, uint32_t obmcLogID)
Matt Spinlercb6b0592019-07-16 15:58:51 -0500201{
Matt Spinler07eefc52019-09-26 11:18:26 -0500202 populateFromRawData(data, obmcLogID);
Matt Spinlercb6b0592019-07-16 15:58:51 -0500203}
204
Matt Spinler07eefc52019-09-26 11:18:26 -0500205void PEL::populateFromRawData(std::vector<uint8_t>& data, uint32_t obmcLogID)
Matt Spinlercb6b0592019-07-16 15:58:51 -0500206{
Matt Spinler07eefc52019-09-26 11:18:26 -0500207 Stream pelData{data};
Matt Spinlercb6b0592019-07-16 15:58:51 -0500208 _ph = std::make_unique<PrivateHeader>(pelData);
209 if (obmcLogID != 0)
210 {
Matt Spinler97d19b42019-10-29 11:34:03 -0500211 _ph->setOBMCLogID(obmcLogID);
Matt Spinlercb6b0592019-07-16 15:58:51 -0500212 }
213
214 _uh = std::make_unique<UserHeader>(pelData);
Matt Spinler131870c2019-09-25 13:29:04 -0500215
216 // Use the section factory to create the rest of the objects
217 for (size_t i = 2; i < _ph->sectionCount(); i++)
218 {
219 auto section = section_factory::create(pelData);
220 _optionalSections.push_back(std::move(section));
221 }
Matt Spinlercb6b0592019-07-16 15:58:51 -0500222}
223
224bool PEL::valid() const
225{
226 bool valid = _ph->valid();
227
228 if (valid)
229 {
230 valid = _uh->valid();
231 }
232
Matt Spinler131870c2019-09-25 13:29:04 -0500233 if (valid)
234 {
235 if (!std::all_of(_optionalSections.begin(), _optionalSections.end(),
236 [](const auto& section) { return section->valid(); }))
237 {
238 valid = false;
239 }
240 }
241
Matt Spinlercb6b0592019-07-16 15:58:51 -0500242 return valid;
243}
244
245void PEL::setCommitTime()
246{
247 auto now = std::chrono::system_clock::now();
Matt Spinler97d19b42019-10-29 11:34:03 -0500248 _ph->setCommitTimestamp(getBCDTime(now));
Matt Spinlercb6b0592019-07-16 15:58:51 -0500249}
250
251void PEL::assignID()
252{
Matt Spinler97d19b42019-10-29 11:34:03 -0500253 _ph->setID(generatePELID());
Matt Spinlercb6b0592019-07-16 15:58:51 -0500254}
255
Matt Spinler06885452019-11-06 10:35:42 -0600256void PEL::flatten(std::vector<uint8_t>& pelBuffer) const
Matt Spinlercb6b0592019-07-16 15:58:51 -0500257{
258 Stream pelData{pelBuffer};
Matt Spinlerb8323632019-09-20 15:11:04 -0500259
Matt Spinler07eefc52019-09-26 11:18:26 -0500260 if (!valid())
Matt Spinlercb6b0592019-07-16 15:58:51 -0500261 {
Matt Spinler07eefc52019-09-26 11:18:26 -0500262 log<level::WARNING>("Unflattening an invalid PEL");
Matt Spinlercb6b0592019-07-16 15:58:51 -0500263 }
264
Matt Spinler07eefc52019-09-26 11:18:26 -0500265 _ph->flatten(pelData);
Matt Spinlerb8323632019-09-20 15:11:04 -0500266 _uh->flatten(pelData);
Matt Spinler07eefc52019-09-26 11:18:26 -0500267
268 for (auto& section : _optionalSections)
269 {
270 section->flatten(pelData);
271 }
Matt Spinlercb6b0592019-07-16 15:58:51 -0500272}
273
Matt Spinler06885452019-11-06 10:35:42 -0600274std::vector<uint8_t> PEL::data() const
Matt Spinlercb6b0592019-07-16 15:58:51 -0500275{
Matt Spinler07eefc52019-09-26 11:18:26 -0500276 std::vector<uint8_t> pelData;
277 flatten(pelData);
278 return pelData;
Matt Spinlercb6b0592019-07-16 15:58:51 -0500279}
280
Matt Spinlerf1b46ff2020-01-22 14:10:04 -0600281size_t PEL::size() const
282{
283 size_t size = 0;
284
285 if (_ph)
286 {
287 size += _ph->header().size;
288 }
289
290 if (_uh)
291 {
292 size += _uh->header().size;
293 }
294
295 for (const auto& section : _optionalSections)
296 {
297 size += section->header().size;
298 }
299
300 return size;
301}
302
Matt Spinlerbd716f02019-10-15 10:54:11 -0500303std::optional<SRC*> PEL::primarySRC() const
304{
305 auto src = std::find_if(
306 _optionalSections.begin(), _optionalSections.end(), [](auto& section) {
307 return section->header().id ==
308 static_cast<uint16_t>(SectionID::primarySRC);
309 });
310 if (src != _optionalSections.end())
311 {
312 return static_cast<SRC*>(src->get());
313 }
314
315 return std::nullopt;
316}
317
Matt Spinlerf1e85e22019-11-01 11:31:31 -0500318void PEL::checkRulesAndFix()
319{
Matt Spinler1f93c592020-09-10 10:43:08 -0500320 // Only fix if the action flags are at their default value which
321 // means they weren't specified in the registry. Otherwise
322 // assume the user knows what they are doing.
323 if (_uh->actionFlags() == actionFlagsDefault)
324 {
325 auto [actionFlags, eventType] =
326 pel_rules::check(0, _uh->eventType(), _uh->severity());
Matt Spinlerf1e85e22019-11-01 11:31:31 -0500327
Matt Spinler1f93c592020-09-10 10:43:08 -0500328 _uh->setActionFlags(actionFlags);
329 _uh->setEventType(eventType);
330 }
Matt Spinlerf1e85e22019-11-01 11:31:31 -0500331}
332
Matt Spinleracb7c102020-01-10 13:49:22 -0600333void PEL::printSectionInJSON(const Section& section, std::string& buf,
Harisuddin Mohamed Isaa214ed32020-02-28 15:58:23 +0800334 std::map<uint16_t, size_t>& pluralSections,
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800335 message::Registry& registry,
336 const std::vector<std::string>& plugins,
337 uint8_t creatorID) const
Aatir186ce8c2019-10-20 15:13:39 -0500338{
339 char tmpB[5];
Aatir Manzurad0e0472019-10-07 13:18:37 -0500340 uint8_t id[] = {static_cast<uint8_t>(section.header().id >> 8),
341 static_cast<uint8_t>(section.header().id)};
342 sprintf(tmpB, "%c%c", id[0], id[1]);
343 std::string sectionID(tmpB);
344 std::string sectionName = pv::sectionTitles.count(sectionID)
345 ? pv::sectionTitles.at(sectionID)
346 : "Unknown Section";
Matt Spinleracb7c102020-01-10 13:49:22 -0600347
348 // Add a count if there are multiple of this type of section
349 auto count = pluralSections.find(section.header().id);
350 if (count != pluralSections.end())
351 {
352 sectionName += " " + std::to_string(count->second);
353 count->second++;
354 }
355
Aatir186ce8c2019-10-20 15:13:39 -0500356 if (section.valid())
357 {
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800358 std::optional<std::string> json;
359 if (sectionID == "PS" || sectionID == "SS")
360 {
Harisuddin Mohamed Isac8d6cc62020-08-19 22:47:19 +0800361 json = section.getJSON(registry, plugins, creatorID);
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800362 }
Matt Spinler386a61e2020-08-13 15:51:12 -0500363 else if ((sectionID == "UD") || (sectionID == "ED"))
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800364 {
Harisuddin Mohamed Isa3fdcd4e2020-08-26 11:56:42 +0800365 json = section.getJSON(creatorID, plugins);
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800366 }
367 else
368 {
369 json = section.getJSON();
370 }
Matt Spinler4220a152020-03-26 10:18:09 -0500371
372 buf += "\"" + sectionName + "\": {\n";
373
Aatir Manzurad0e0472019-10-07 13:18:37 -0500374 if (json)
375 {
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800376 buf += *json + "\n},\n";
Aatir Manzurad0e0472019-10-07 13:18:37 -0500377 }
378 else
379 {
Matt Spinler4220a152020-03-26 10:18:09 -0500380 jsonInsert(buf, pv::sectionVer,
381 getNumberString("%d", section.header().version), 1);
382 jsonInsert(buf, pv::subSection,
383 getNumberString("%d", section.header().subType), 1);
384 jsonInsert(buf, pv::createdBy,
385 getNumberString("0x%X", section.header().componentID),
386 1);
387
Aatir Manzurad0e0472019-10-07 13:18:37 -0500388 std::vector<uint8_t> data;
389 Stream s{data};
390 section.flatten(s);
Matt Spinler4220a152020-03-26 10:18:09 -0500391 std::string dstr =
392 dumpHex(std::data(data) + SectionHeader::flattenedSize(),
Harisuddin Mohamed Isa097ad122020-06-11 21:19:41 +0800393 data.size() - SectionHeader::flattenedSize(), 2);
Matt Spinler4220a152020-03-26 10:18:09 -0500394 std::string jsonIndent(indentLevel, 0x20);
395 buf += jsonIndent + "\"Data\": [\n";
396 buf += dstr;
397 buf += jsonIndent + "]\n";
398 buf += "},\n";
Aatir Manzurad0e0472019-10-07 13:18:37 -0500399 }
Aatir186ce8c2019-10-20 15:13:39 -0500400 }
401 else
402 {
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800403 buf += "\n\"Invalid Section\": [\n \"invalid\"\n],\n";
Aatir186ce8c2019-10-20 15:13:39 -0500404 }
405}
406
Matt Spinleracb7c102020-01-10 13:49:22 -0600407std::map<uint16_t, size_t> PEL::getPluralSections() const
408{
409 std::map<uint16_t, size_t> sectionCounts;
410
411 for (const auto& section : optionalSections())
412 {
413 if (sectionCounts.find(section->header().id) == sectionCounts.end())
414 {
415 sectionCounts[section->header().id] = 1;
416 }
417 else
418 {
419 sectionCounts[section->header().id]++;
420 }
421 }
422
423 std::map<uint16_t, size_t> sections;
424 for (const auto& [id, count] : sectionCounts)
425 {
426 if (count > 1)
427 {
428 // Start with 0 here and printSectionInJSON()
429 // will increment it as it goes.
430 sections.emplace(id, 0);
431 }
432 }
433
434 return sections;
435}
436
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800437void PEL::toJSON(message::Registry& registry,
438 const std::vector<std::string>& plugins) const
Aatir186ce8c2019-10-20 15:13:39 -0500439{
Matt Spinleracb7c102020-01-10 13:49:22 -0600440 auto sections = getPluralSections();
441
Harisuddin Mohamed Isaa214ed32020-02-28 15:58:23 +0800442 std::string buf = "{\n";
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800443 printSectionInJSON(*(_ph.get()), buf, sections, registry, plugins);
444 printSectionInJSON(*(_uh.get()), buf, sections, registry, plugins);
Aatir186ce8c2019-10-20 15:13:39 -0500445 for (auto& section : this->optionalSections())
446 {
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800447 printSectionInJSON(*(section.get()), buf, sections, registry, plugins,
448 _ph->creatorID());
Aatir186ce8c2019-10-20 15:13:39 -0500449 }
450 buf += "}";
451 std::size_t found = buf.rfind(",");
452 if (found != std::string::npos)
453 buf.replace(found, 1, "");
454 std::cout << buf << std::endl;
455}
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800456
Matt Spinler85f61a62020-06-03 16:28:55 -0500457bool PEL::addUserDataSection(std::unique_ptr<UserData> userData)
458{
459 if (size() + userData->header().size > _maxPELSize)
460 {
461 if (userData->shrink(_maxPELSize - size()))
462 {
463 _optionalSections.push_back(std::move(userData));
464 }
465 else
466 {
467 log<level::WARNING>(
468 "Could not shrink UserData section. Dropping",
469 entry("SECTION_SIZE=%d\n", userData->header().size),
470 entry("COMPONENT_ID=0x%02X", userData->header().componentID),
471 entry("SUBTYPE=0x%X", userData->header().subType),
472 entry("VERSION=0x%X", userData->header().version));
473 return false;
474 }
475 }
476 else
477 {
478 _optionalSections.push_back(std::move(userData));
479 }
480 return true;
481}
482
Matt Spinler5a90a952020-08-27 09:39:03 -0500483nlohmann::json PEL::getCalloutJSON(const PelFFDC& ffdcFiles)
484{
485 nlohmann::json callouts;
486
487 for (const auto& file : ffdcFiles)
488 {
489 if ((file.format == UserDataFormat::json) &&
490 (file.subType == jsonCalloutSubtype))
491 {
492 auto data = util::readFD(file.fd);
493 if (data.empty())
494 {
495 throw std::runtime_error{
496 "Could not get data from JSON callout file descriptor"};
497 }
498
499 std::string jsonString{data.begin(), data.begin() + data.size()};
500
501 callouts = nlohmann::json::parse(jsonString);
502 break;
503 }
504 }
505
506 return callouts;
507}
508
Andrew Geissler44fc3162020-07-09 09:21:31 -0500509bool PEL::isCalloutPresent() const
510{
511 auto pSRC = primarySRC();
512 if (!pSRC)
513 {
514 return false;
515 }
516
517 bool calloutPresent = false;
518 if ((*pSRC)->callouts())
519 {
520 for (auto& i : (*pSRC)->callouts()->callouts())
521 {
522 if (((*i).fruIdentity()))
523 {
524 auto& fruId = (*i).fruIdentity();
525 if ((*fruId).failingComponentType() != 0)
526 {
527 calloutPresent = true;
528 break;
529 }
530 }
531 }
532 }
533
534 return calloutPresent;
535}
536
Sumit Kumar3160a542021-04-26 08:07:04 -0500537void PEL::updateSysInfoInExtendedUserDataSection(
538 const DataInterfaceBase& dataIface)
539{
540 const AdditionalData additionalData;
541
542 // Check for PEL from Hostboot
543 if (_ph->creatorID() == static_cast<uint8_t>(CreatorID::hostboot))
544 {
545 // Get the ED section from PEL
546 auto op = std::find_if(_optionalSections.begin(),
547 _optionalSections.end(), [](auto& section) {
548 return section->header().id ==
549 static_cast<uint16_t>(
550 SectionID::extUserData);
551 });
552
553 // Check for ED section found and its not the last section of PEL
554 if (op != _optionalSections.end())
555 {
556 // Get the extended user data class mapped to found section
557 auto extUserData = static_cast<ExtendedUserData*>(op->get());
558
559 // Check for the creator ID is for OpenBMC
560 if (extUserData->creatorID() ==
561 static_cast<uint8_t>(CreatorID::openBMC))
562 {
563 // Update subtype and component id
564 auto subType = static_cast<uint8_t>(UserDataFormat::json);
565 auto componentId =
566 static_cast<uint16_t>(ComponentID::phosphorLogging);
567
568 // Update system data to ED section
569 auto ud =
570 util::makeSysInfoUserDataSection(additionalData, dataIface);
571 extUserData->updateDataSection(subType, componentId,
572 ud->data());
573 }
574 }
575 }
576}
577
Sumit Kumar3e274432021-09-14 06:37:56 -0500578void PEL::updateTerminateBitInSRCSection()
579{
580 // Check for pel severity of type - 0x51 = critical error, system
581 // termination
582 if (_uh->severity() == 0x51)
583 {
584 // Get the primary SRC section
585 auto pSRC = primarySRC();
586 if (pSRC)
587 {
588 (*pSRC)->setTerminateBit();
589 }
590 }
591}
592
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600593namespace util
594{
595
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600596std::unique_ptr<UserData> makeJSONUserDataSection(const nlohmann::json& json)
597{
598 auto jsonString = json.dump();
599 std::vector<uint8_t> jsonData(jsonString.begin(), jsonString.end());
600
601 // Pad to a 4 byte boundary
602 while ((jsonData.size() % 4) != 0)
603 {
604 jsonData.push_back(0);
605 }
606
607 return std::make_unique<UserData>(
608 static_cast<uint16_t>(ComponentID::phosphorLogging),
609 static_cast<uint8_t>(UserDataFormat::json),
610 static_cast<uint8_t>(UserDataFormatVersion::json), jsonData);
611}
612
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600613std::unique_ptr<UserData> makeADUserDataSection(const AdditionalData& ad)
614{
615 assert(!ad.empty());
616 nlohmann::json json;
617
618 // Remove the 'ESEL' entry, as it contains a full PEL in the value.
619 if (ad.getValue("ESEL"))
620 {
621 auto newAD = ad;
622 newAD.remove("ESEL");
623 json = newAD.toJSON();
624 }
625 else
626 {
627 json = ad.toJSON();
628 }
629
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600630 return makeJSONUserDataSection(json);
631}
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600632
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600633void addProcessNameToJSON(nlohmann::json& json,
634 const std::optional<std::string>& pid,
635 const DataInterfaceBase& dataIface)
636{
Matt Spinler677381b2020-01-23 10:04:29 -0600637 std::string name{unknownValue};
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600638
639 try
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600640 {
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600641 if (pid)
642 {
643 auto n = dataIface.getProcessName(*pid);
644 if (n)
645 {
646 name = *n;
647 }
648 }
649 }
Patrick Williams66491c62021-10-06 12:23:37 -0500650 catch (const std::exception& e)
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600651 {
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600652 }
653
Sumit Kumar3160a542021-04-26 08:07:04 -0500654 if (pid)
655 {
656 json["Process Name"] = std::move(name);
657 }
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600658}
659
Matt Spinler677381b2020-01-23 10:04:29 -0600660void addBMCFWVersionIDToJSON(nlohmann::json& json,
661 const DataInterfaceBase& dataIface)
662{
663 auto id = dataIface.getBMCFWVersionID();
664 if (id.empty())
665 {
666 id = unknownValue;
667 }
668
Matt Spinlerc2b8a512021-05-21 12:44:42 -0600669 json["FW Version ID"] = std::move(id);
Matt Spinler677381b2020-01-23 10:04:29 -0600670}
671
Matt Spinler4aa23a12020-02-03 15:05:09 -0600672std::string lastSegment(char separator, std::string data)
673{
674 auto pos = data.find_last_of(separator);
675 if (pos != std::string::npos)
676 {
677 data = data.substr(pos + 1);
678 }
679
680 return data;
681}
682
Ben Tynere32b7e72021-05-18 12:38:40 -0500683void addIMKeyword(nlohmann::json& json, const DataInterfaceBase& dataIface)
684{
685 auto keyword = dataIface.getSystemIMKeyword();
686
687 std::string value{};
688
689 std::for_each(keyword.begin(), keyword.end(), [&](const auto& byte) {
690 value += fmt::format("{:02X}", byte);
691 });
692
693 json["System IM"] = value;
694}
695
Matt Spinler4aa23a12020-02-03 15:05:09 -0600696void addStatesToJSON(nlohmann::json& json, const DataInterfaceBase& dataIface)
697{
698 json["BMCState"] = lastSegment('.', dataIface.getBMCState());
699 json["ChassisState"] = lastSegment('.', dataIface.getChassisState());
700 json["HostState"] = lastSegment('.', dataIface.getHostState());
Sumit Kumar2c36fdd2021-09-21 03:12:11 -0500701 json["BootState"] = lastSegment('.', dataIface.getBootState());
Matt Spinler4aa23a12020-02-03 15:05:09 -0600702}
703
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600704std::unique_ptr<UserData>
705 makeSysInfoUserDataSection(const AdditionalData& ad,
706 const DataInterfaceBase& dataIface)
707{
708 nlohmann::json json;
709
710 addProcessNameToJSON(json, ad.getValue("_PID"), dataIface);
Matt Spinler677381b2020-01-23 10:04:29 -0600711 addBMCFWVersionIDToJSON(json, dataIface);
Ben Tynere32b7e72021-05-18 12:38:40 -0500712 addIMKeyword(json, dataIface);
Matt Spinler4aa23a12020-02-03 15:05:09 -0600713 addStatesToJSON(json, dataIface);
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600714
715 return makeJSONUserDataSection(json);
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600716}
717
Matt Spinler5b289b22020-03-26 14:27:19 -0500718std::vector<uint8_t> readFD(int fd)
719{
720 std::vector<uint8_t> data;
721
722 // Get the size
723 struct stat s;
724 int r = fstat(fd, &s);
725 if (r != 0)
726 {
727 auto e = errno;
728 log<level::ERR>("Could not get FFDC file size from FD",
729 entry("ERRNO=%d", e));
730 return data;
731 }
732
733 if (0 == s.st_size)
734 {
735 log<level::ERR>("FFDC file is empty");
736 return data;
737 }
738
739 data.resize(s.st_size);
740
741 // Make sure its at the beginning, as maybe another
742 // extension already used it.
743 r = lseek(fd, 0, SEEK_SET);
744 if (r == -1)
745 {
746 auto e = errno;
747 log<level::ERR>("Could not seek to beginning of FFDC file",
748 entry("ERRNO=%d", e));
749 return data;
750 }
751
752 r = read(fd, data.data(), s.st_size);
753 if (r == -1)
754 {
755 auto e = errno;
756 log<level::ERR>("Could not read FFDC file", entry("ERRNO=%d", e));
757 }
758 else if (r != s.st_size)
759 {
760 log<level::WARNING>("Could not read full FFDC file",
761 entry("FILE_SIZE=%d", s.st_size),
762 entry("SIZE_READ=%d", r));
763 }
764
765 return data;
766}
767
Matt Spinler56ad2a02020-03-26 14:00:52 -0500768std::unique_ptr<UserData> makeFFDCuserDataSection(uint16_t componentID,
769 const PelFFDCfile& file)
770{
Matt Spinler5b289b22020-03-26 14:27:19 -0500771 auto data = readFD(file.fd);
772
773 if (data.empty())
774 {
775 return std::unique_ptr<UserData>();
776 }
777
778 // The data needs 4 Byte alignment, and save amount padded for the
779 // CBOR case.
780 uint32_t pad = 0;
781 while (data.size() % 4)
782 {
783 data.push_back(0);
784 pad++;
785 }
786
787 // For JSON, CBOR, and Text use our component ID, subType, and version,
788 // otherwise use the supplied ones.
789 uint16_t compID = static_cast<uint16_t>(ComponentID::phosphorLogging);
790 uint8_t subType{};
791 uint8_t version{};
792
793 switch (file.format)
794 {
795 case UserDataFormat::json:
796 subType = static_cast<uint8_t>(UserDataFormat::json);
797 version = static_cast<uint8_t>(UserDataFormatVersion::json);
798 break;
799 case UserDataFormat::cbor:
800 subType = static_cast<uint8_t>(UserDataFormat::cbor);
801 version = static_cast<uint8_t>(UserDataFormatVersion::cbor);
802
803 // The CBOR parser will fail on the extra pad bytes since they
804 // aren't CBOR. Add the amount we padded to the end and other
805 // code will remove it all before parsing.
806 {
807 data.resize(data.size() + 4);
808 Stream stream{data};
809 stream.offset(data.size() - 4);
810 stream << pad;
811 }
812
813 break;
814 case UserDataFormat::text:
815 subType = static_cast<uint8_t>(UserDataFormat::text);
816 version = static_cast<uint8_t>(UserDataFormatVersion::text);
817 break;
818 case UserDataFormat::custom:
819 default:
820 // Use the passed in values
821 compID = componentID;
822 subType = file.subType;
823 version = file.version;
824 break;
825 }
826
827 return std::make_unique<UserData>(compID, subType, version, data);
Matt Spinler56ad2a02020-03-26 14:00:52 -0500828}
829
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600830} // namespace util
831
Matt Spinlercb6b0592019-07-16 15:58:51 -0500832} // namespace pels
833} // namespace openpower