blob: de70b530144484f7504d2a937f351cc198846d9d [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
Ben Tynere32b7e72021-05-18 12:38:40 -050039#include <fmt/format.h>
Matt Spinler5b289b22020-03-26 14:27:19 -050040#include <sys/stat.h>
41#include <unistd.h>
42
Aatir186ce8c2019-10-20 15:13:39 -050043#include <iostream>
Matt Spinler07eefc52019-09-26 11:18:26 -050044#include <phosphor-logging/log.hpp>
45
Matt Spinlercb6b0592019-07-16 15:58:51 -050046namespace openpower
47{
48namespace pels
49{
Matt Spinlerb8323632019-09-20 15:11:04 -050050namespace message = openpower::pels::message;
Aatir186ce8c2019-10-20 15:13:39 -050051namespace pv = openpower::pels::pel_values;
Matt Spinler4bfc9082020-03-24 15:05:54 -050052using namespace phosphor::logging;
Matt Spinlerb8323632019-09-20 15:11:04 -050053
Matt Spinler677381b2020-01-23 10:04:29 -060054constexpr auto unknownValue = "Unknown";
55
Matt Spinler4bfc9082020-03-24 15:05:54 -050056PEL::PEL(const message::Entry& regEntry, uint32_t obmcLogID, uint64_t timestamp,
Matt Spinlerbd716f02019-10-15 10:54:11 -050057 phosphor::logging::Entry::Level severity,
Jayanth Othayothe8bdeea2021-06-03 03:01:16 -050058 const AdditionalData& additionalData, const PelFFDC& ffdcFilesIn,
Matt Spinleraa659472019-10-23 09:26:48 -050059 const DataInterfaceBase& dataIface)
Matt Spinlerb8323632019-09-20 15:11:04 -050060{
Jayanth Othayothe8bdeea2021-06-03 03:01:16 -050061 // No changes in input, for non SBE error related requests
62 PelFFDC ffdcFiles = ffdcFilesIn;
63
Jayanth Othayoth92b20662021-11-05 00:09:15 -050064#ifdef PEL_ENABLE_PHAL
Jayanth Othayothe8bdeea2021-06-03 03:01:16 -050065 // Add sbe ffdc processed data into ffdcfiles.
66 namespace sbe = openpower::pels::sbe;
67 auto processReq =
68 std::any_of(ffdcFiles.begin(), ffdcFiles.end(), [](const auto& file) {
69 return file.format == UserDataFormat::custom &&
70 file.subType == sbe::sbeFFDCSubType;
71 });
72 // sbeFFDC can't be destroyed until the end of the PEL constructor
73 // because it needs to keep around the FFDC Files to be used below.
74 std::unique_ptr<sbe::SbeFFDC> sbeFFDCPtr;
75 if (processReq)
76 {
77 sbeFFDCPtr =
78 std::make_unique<sbe::SbeFFDC>(additionalData, ffdcFilesIn);
79 const auto& sbeFFDCFiles = sbeFFDCPtr->getSbeFFDC();
80 ffdcFiles.insert(ffdcFiles.end(), sbeFFDCFiles.begin(),
81 sbeFFDCFiles.end());
82 }
83#endif
84
Matt Spinler85f61a62020-06-03 16:28:55 -050085 std::map<std::string, std::vector<std::string>> debugData;
Matt Spinler5a90a952020-08-27 09:39:03 -050086 nlohmann::json callouts;
Matt Spinler85f61a62020-06-03 16:28:55 -050087
Matt Spinler4bfc9082020-03-24 15:05:54 -050088 _ph = std::make_unique<PrivateHeader>(regEntry.componentID, obmcLogID,
Matt Spinlerb8323632019-09-20 15:11:04 -050089 timestamp);
Vijay Lobo6b3f3452021-04-15 23:04:42 -050090 _uh = std::make_unique<UserHeader>(regEntry, severity, additionalData,
91 dataIface);
Matt Spinlerb8323632019-09-20 15:11:04 -050092
Matt Spinler5a90a952020-08-27 09:39:03 -050093 // Extract any callouts embedded in an FFDC file.
94 if (!ffdcFiles.empty())
95 {
96 try
97 {
98 callouts = getCalloutJSON(ffdcFiles);
99 }
100 catch (const std::exception& e)
101 {
102 debugData.emplace("FFDC file JSON callouts error",
103 std::vector<std::string>{e.what()});
104 }
105 }
106
107 auto src =
108 std::make_unique<SRC>(regEntry, additionalData, callouts, dataIface);
109
Matt Spinler85f61a62020-06-03 16:28:55 -0500110 if (!src->getDebugData().empty())
111 {
112 // Something didn't go as planned
113 debugData.emplace("SRC", src->getDebugData());
114 }
Matt Spinlerc63e2e82019-12-02 15:50:12 -0600115
Matt Spinler4bfc9082020-03-24 15:05:54 -0500116 auto euh = std::make_unique<ExtendedUserHeader>(dataIface, regEntry, *src);
Matt Spinlerc63e2e82019-12-02 15:50:12 -0600117
Matt Spinlerbd716f02019-10-15 10:54:11 -0500118 _optionalSections.push_back(std::move(src));
Matt Spinlerc63e2e82019-12-02 15:50:12 -0600119 _optionalSections.push_back(std::move(euh));
Matt Spinlerb8323632019-09-20 15:11:04 -0500120
Matt Spinleraa659472019-10-23 09:26:48 -0500121 auto mtms = std::make_unique<FailingMTMS>(dataIface);
122 _optionalSections.push_back(std::move(mtms));
Matt Spinlerbd716f02019-10-15 10:54:11 -0500123
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600124 auto ud = util::makeSysInfoUserDataSection(additionalData, dataIface);
Matt Spinler85f61a62020-06-03 16:28:55 -0500125 addUserDataSection(std::move(ud));
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600126
Sumit Kumar3e274432021-09-14 06:37:56 -0500127 // Check for pel severity of type - 0x51 = critical error, system
128 // termination and update terminate bit in SRC for pels
129 updateTerminateBitInSRCSection();
130
Matt Spinler9b7e94f2020-03-24 15:44:41 -0500131 // Create a UserData section from AdditionalData.
Matt Spinlerafa857c2019-10-24 13:03:46 -0500132 if (!additionalData.empty())
133 {
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600134 ud = util::makeADUserDataSection(additionalData);
Matt Spinler85f61a62020-06-03 16:28:55 -0500135 addUserDataSection(std::move(ud));
Matt Spinlerafa857c2019-10-24 13:03:46 -0500136 }
137
Matt Spinler56ad2a02020-03-26 14:00:52 -0500138 // Add any FFDC files into UserData sections
139 for (const auto& file : ffdcFiles)
140 {
141 ud = util::makeFFDCuserDataSection(regEntry.componentID, file);
142 if (!ud)
143 {
Matt Spinler85f61a62020-06-03 16:28:55 -0500144 // Add this error into the debug data UserData section
145 std::ostringstream msg;
146 msg << "Could not make PEL FFDC UserData section from file"
147 << std::hex << regEntry.componentID << " " << file.subType
148 << " " << file.version;
149 if (debugData.count("FFDC File"))
150 {
151 debugData.at("FFDC File").push_back(msg.str());
152 }
153 else
154 {
155 debugData.emplace("FFDC File",
156 std::vector<std::string>{msg.str()});
157 }
158
Matt Spinler56ad2a02020-03-26 14:00:52 -0500159 continue;
160 }
161
Matt Spinler85f61a62020-06-03 16:28:55 -0500162 addUserDataSection(std::move(ud));
163 }
Matt Spinler56ad2a02020-03-26 14:00:52 -0500164
Jayanth Othayothda9b5832021-11-05 04:19:43 -0500165#ifdef PEL_ENABLE_PHAL
166 auto path = std::string(OBJ_ENTRY) + '/' + std::to_string(obmcLogID);
Jayanth Othayoth3ef7b602021-11-09 06:40:38 -0600167 openpower::pels::phal::createServiceActions(callouts, path, dataIface,
168 plid());
Jayanth Othayothda9b5832021-11-05 04:19:43 -0500169#endif
170
Matt Spinler85f61a62020-06-03 16:28:55 -0500171 // Store in the PEL any important debug data created while
172 // building the PEL sections.
173 if (!debugData.empty())
174 {
175 nlohmann::json data;
176 data["PEL Internal Debug Data"] = debugData;
177 ud = util::makeJSONUserDataSection(data);
178
179 addUserDataSection(std::move(ud));
180
181 // Also put in the journal for debug
182 for (const auto& [name, data] : debugData)
183 {
184 for (const auto& message : data)
185 {
186 std::string entry = name + ": " + message;
187 log<level::INFO>(entry.c_str());
Matt Spinler56ad2a02020-03-26 14:00:52 -0500188 }
189 }
Matt Spinler56ad2a02020-03-26 14:00:52 -0500190 }
191
Matt Spinler97d19b42019-10-29 11:34:03 -0500192 _ph->setSectionCount(2 + _optionalSections.size());
Matt Spinlerf1e85e22019-11-01 11:31:31 -0500193
194 checkRulesAndFix();
Matt Spinlerb8323632019-09-20 15:11:04 -0500195}
Matt Spinlercb6b0592019-07-16 15:58:51 -0500196
Matt Spinler07eefc52019-09-26 11:18:26 -0500197PEL::PEL(std::vector<uint8_t>& data) : PEL(data, 0)
Matt Spinlercb6b0592019-07-16 15:58:51 -0500198{
199}
200
Matt Spinler07eefc52019-09-26 11:18:26 -0500201PEL::PEL(std::vector<uint8_t>& data, uint32_t obmcLogID)
Matt Spinlercb6b0592019-07-16 15:58:51 -0500202{
Matt Spinler07eefc52019-09-26 11:18:26 -0500203 populateFromRawData(data, obmcLogID);
Matt Spinlercb6b0592019-07-16 15:58:51 -0500204}
205
Matt Spinler07eefc52019-09-26 11:18:26 -0500206void PEL::populateFromRawData(std::vector<uint8_t>& data, uint32_t obmcLogID)
Matt Spinlercb6b0592019-07-16 15:58:51 -0500207{
Matt Spinler07eefc52019-09-26 11:18:26 -0500208 Stream pelData{data};
Matt Spinlercb6b0592019-07-16 15:58:51 -0500209 _ph = std::make_unique<PrivateHeader>(pelData);
210 if (obmcLogID != 0)
211 {
Matt Spinler97d19b42019-10-29 11:34:03 -0500212 _ph->setOBMCLogID(obmcLogID);
Matt Spinlercb6b0592019-07-16 15:58:51 -0500213 }
214
215 _uh = std::make_unique<UserHeader>(pelData);
Matt Spinler131870c2019-09-25 13:29:04 -0500216
217 // Use the section factory to create the rest of the objects
218 for (size_t i = 2; i < _ph->sectionCount(); i++)
219 {
220 auto section = section_factory::create(pelData);
221 _optionalSections.push_back(std::move(section));
222 }
Matt Spinlercb6b0592019-07-16 15:58:51 -0500223}
224
225bool PEL::valid() const
226{
227 bool valid = _ph->valid();
228
229 if (valid)
230 {
231 valid = _uh->valid();
232 }
233
Matt Spinler131870c2019-09-25 13:29:04 -0500234 if (valid)
235 {
236 if (!std::all_of(_optionalSections.begin(), _optionalSections.end(),
237 [](const auto& section) { return section->valid(); }))
238 {
239 valid = false;
240 }
241 }
242
Matt Spinlercb6b0592019-07-16 15:58:51 -0500243 return valid;
244}
245
246void PEL::setCommitTime()
247{
248 auto now = std::chrono::system_clock::now();
Matt Spinler97d19b42019-10-29 11:34:03 -0500249 _ph->setCommitTimestamp(getBCDTime(now));
Matt Spinlercb6b0592019-07-16 15:58:51 -0500250}
251
252void PEL::assignID()
253{
Matt Spinler97d19b42019-10-29 11:34:03 -0500254 _ph->setID(generatePELID());
Matt Spinlercb6b0592019-07-16 15:58:51 -0500255}
256
Matt Spinler06885452019-11-06 10:35:42 -0600257void PEL::flatten(std::vector<uint8_t>& pelBuffer) const
Matt Spinlercb6b0592019-07-16 15:58:51 -0500258{
259 Stream pelData{pelBuffer};
Matt Spinlerb8323632019-09-20 15:11:04 -0500260
Matt Spinler07eefc52019-09-26 11:18:26 -0500261 if (!valid())
Matt Spinlercb6b0592019-07-16 15:58:51 -0500262 {
Matt Spinler07eefc52019-09-26 11:18:26 -0500263 log<level::WARNING>("Unflattening an invalid PEL");
Matt Spinlercb6b0592019-07-16 15:58:51 -0500264 }
265
Matt Spinler07eefc52019-09-26 11:18:26 -0500266 _ph->flatten(pelData);
Matt Spinlerb8323632019-09-20 15:11:04 -0500267 _uh->flatten(pelData);
Matt Spinler07eefc52019-09-26 11:18:26 -0500268
269 for (auto& section : _optionalSections)
270 {
271 section->flatten(pelData);
272 }
Matt Spinlercb6b0592019-07-16 15:58:51 -0500273}
274
Matt Spinler06885452019-11-06 10:35:42 -0600275std::vector<uint8_t> PEL::data() const
Matt Spinlercb6b0592019-07-16 15:58:51 -0500276{
Matt Spinler07eefc52019-09-26 11:18:26 -0500277 std::vector<uint8_t> pelData;
278 flatten(pelData);
279 return pelData;
Matt Spinlercb6b0592019-07-16 15:58:51 -0500280}
281
Matt Spinlerf1b46ff2020-01-22 14:10:04 -0600282size_t PEL::size() const
283{
284 size_t size = 0;
285
286 if (_ph)
287 {
288 size += _ph->header().size;
289 }
290
291 if (_uh)
292 {
293 size += _uh->header().size;
294 }
295
296 for (const auto& section : _optionalSections)
297 {
298 size += section->header().size;
299 }
300
301 return size;
302}
303
Matt Spinlerbd716f02019-10-15 10:54:11 -0500304std::optional<SRC*> PEL::primarySRC() const
305{
306 auto src = std::find_if(
307 _optionalSections.begin(), _optionalSections.end(), [](auto& section) {
308 return section->header().id ==
309 static_cast<uint16_t>(SectionID::primarySRC);
310 });
311 if (src != _optionalSections.end())
312 {
313 return static_cast<SRC*>(src->get());
314 }
315
316 return std::nullopt;
317}
318
Matt Spinlerf1e85e22019-11-01 11:31:31 -0500319void PEL::checkRulesAndFix()
320{
Matt Spinler1f93c592020-09-10 10:43:08 -0500321 // Only fix if the action flags are at their default value which
322 // means they weren't specified in the registry. Otherwise
323 // assume the user knows what they are doing.
324 if (_uh->actionFlags() == actionFlagsDefault)
325 {
326 auto [actionFlags, eventType] =
327 pel_rules::check(0, _uh->eventType(), _uh->severity());
Matt Spinlerf1e85e22019-11-01 11:31:31 -0500328
Matt Spinler1f93c592020-09-10 10:43:08 -0500329 _uh->setActionFlags(actionFlags);
330 _uh->setEventType(eventType);
331 }
Matt Spinlerf1e85e22019-11-01 11:31:31 -0500332}
333
Matt Spinleracb7c102020-01-10 13:49:22 -0600334void PEL::printSectionInJSON(const Section& section, std::string& buf,
Harisuddin Mohamed Isaa214ed32020-02-28 15:58:23 +0800335 std::map<uint16_t, size_t>& pluralSections,
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800336 message::Registry& registry,
337 const std::vector<std::string>& plugins,
338 uint8_t creatorID) const
Aatir186ce8c2019-10-20 15:13:39 -0500339{
340 char tmpB[5];
Aatir Manzurad0e0472019-10-07 13:18:37 -0500341 uint8_t id[] = {static_cast<uint8_t>(section.header().id >> 8),
342 static_cast<uint8_t>(section.header().id)};
343 sprintf(tmpB, "%c%c", id[0], id[1]);
344 std::string sectionID(tmpB);
345 std::string sectionName = pv::sectionTitles.count(sectionID)
346 ? pv::sectionTitles.at(sectionID)
347 : "Unknown Section";
Matt Spinleracb7c102020-01-10 13:49:22 -0600348
349 // Add a count if there are multiple of this type of section
350 auto count = pluralSections.find(section.header().id);
351 if (count != pluralSections.end())
352 {
353 sectionName += " " + std::to_string(count->second);
354 count->second++;
355 }
356
Aatir186ce8c2019-10-20 15:13:39 -0500357 if (section.valid())
358 {
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800359 std::optional<std::string> json;
360 if (sectionID == "PS" || sectionID == "SS")
361 {
Harisuddin Mohamed Isac8d6cc62020-08-19 22:47:19 +0800362 json = section.getJSON(registry, plugins, creatorID);
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800363 }
Matt Spinler386a61e2020-08-13 15:51:12 -0500364 else if ((sectionID == "UD") || (sectionID == "ED"))
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800365 {
Harisuddin Mohamed Isa3fdcd4e2020-08-26 11:56:42 +0800366 json = section.getJSON(creatorID, plugins);
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800367 }
368 else
369 {
370 json = section.getJSON();
371 }
Matt Spinler4220a152020-03-26 10:18:09 -0500372
373 buf += "\"" + sectionName + "\": {\n";
374
Aatir Manzurad0e0472019-10-07 13:18:37 -0500375 if (json)
376 {
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800377 buf += *json + "\n},\n";
Aatir Manzurad0e0472019-10-07 13:18:37 -0500378 }
379 else
380 {
Matt Spinler4220a152020-03-26 10:18:09 -0500381 jsonInsert(buf, pv::sectionVer,
382 getNumberString("%d", section.header().version), 1);
383 jsonInsert(buf, pv::subSection,
384 getNumberString("%d", section.header().subType), 1);
385 jsonInsert(buf, pv::createdBy,
386 getNumberString("0x%X", section.header().componentID),
387 1);
388
Aatir Manzurad0e0472019-10-07 13:18:37 -0500389 std::vector<uint8_t> data;
390 Stream s{data};
391 section.flatten(s);
Matt Spinler4220a152020-03-26 10:18:09 -0500392 std::string dstr =
393 dumpHex(std::data(data) + SectionHeader::flattenedSize(),
Harisuddin Mohamed Isa097ad122020-06-11 21:19:41 +0800394 data.size() - SectionHeader::flattenedSize(), 2);
Matt Spinler4220a152020-03-26 10:18:09 -0500395 std::string jsonIndent(indentLevel, 0x20);
396 buf += jsonIndent + "\"Data\": [\n";
397 buf += dstr;
398 buf += jsonIndent + "]\n";
399 buf += "},\n";
Aatir Manzurad0e0472019-10-07 13:18:37 -0500400 }
Aatir186ce8c2019-10-20 15:13:39 -0500401 }
402 else
403 {
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800404 buf += "\n\"Invalid Section\": [\n \"invalid\"\n],\n";
Aatir186ce8c2019-10-20 15:13:39 -0500405 }
406}
407
Matt Spinleracb7c102020-01-10 13:49:22 -0600408std::map<uint16_t, size_t> PEL::getPluralSections() const
409{
410 std::map<uint16_t, size_t> sectionCounts;
411
412 for (const auto& section : optionalSections())
413 {
414 if (sectionCounts.find(section->header().id) == sectionCounts.end())
415 {
416 sectionCounts[section->header().id] = 1;
417 }
418 else
419 {
420 sectionCounts[section->header().id]++;
421 }
422 }
423
424 std::map<uint16_t, size_t> sections;
425 for (const auto& [id, count] : sectionCounts)
426 {
427 if (count > 1)
428 {
429 // Start with 0 here and printSectionInJSON()
430 // will increment it as it goes.
431 sections.emplace(id, 0);
432 }
433 }
434
435 return sections;
436}
437
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800438void PEL::toJSON(message::Registry& registry,
439 const std::vector<std::string>& plugins) const
Aatir186ce8c2019-10-20 15:13:39 -0500440{
Matt Spinleracb7c102020-01-10 13:49:22 -0600441 auto sections = getPluralSections();
442
Harisuddin Mohamed Isaa214ed32020-02-28 15:58:23 +0800443 std::string buf = "{\n";
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800444 printSectionInJSON(*(_ph.get()), buf, sections, registry, plugins);
445 printSectionInJSON(*(_uh.get()), buf, sections, registry, plugins);
Aatir186ce8c2019-10-20 15:13:39 -0500446 for (auto& section : this->optionalSections())
447 {
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800448 printSectionInJSON(*(section.get()), buf, sections, registry, plugins,
449 _ph->creatorID());
Aatir186ce8c2019-10-20 15:13:39 -0500450 }
451 buf += "}";
452 std::size_t found = buf.rfind(",");
453 if (found != std::string::npos)
454 buf.replace(found, 1, "");
455 std::cout << buf << std::endl;
456}
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800457
Matt Spinler85f61a62020-06-03 16:28:55 -0500458bool PEL::addUserDataSection(std::unique_ptr<UserData> userData)
459{
460 if (size() + userData->header().size > _maxPELSize)
461 {
462 if (userData->shrink(_maxPELSize - size()))
463 {
464 _optionalSections.push_back(std::move(userData));
465 }
466 else
467 {
468 log<level::WARNING>(
469 "Could not shrink UserData section. Dropping",
470 entry("SECTION_SIZE=%d\n", userData->header().size),
471 entry("COMPONENT_ID=0x%02X", userData->header().componentID),
472 entry("SUBTYPE=0x%X", userData->header().subType),
473 entry("VERSION=0x%X", userData->header().version));
474 return false;
475 }
476 }
477 else
478 {
479 _optionalSections.push_back(std::move(userData));
480 }
481 return true;
482}
483
Matt Spinler5a90a952020-08-27 09:39:03 -0500484nlohmann::json PEL::getCalloutJSON(const PelFFDC& ffdcFiles)
485{
486 nlohmann::json callouts;
487
488 for (const auto& file : ffdcFiles)
489 {
490 if ((file.format == UserDataFormat::json) &&
491 (file.subType == jsonCalloutSubtype))
492 {
493 auto data = util::readFD(file.fd);
494 if (data.empty())
495 {
496 throw std::runtime_error{
497 "Could not get data from JSON callout file descriptor"};
498 }
499
500 std::string jsonString{data.begin(), data.begin() + data.size()};
501
502 callouts = nlohmann::json::parse(jsonString);
503 break;
504 }
505 }
506
507 return callouts;
508}
509
Andrew Geisslerf8e750d2022-01-14 14:56:13 -0600510bool PEL::isHwCalloutPresent() const
Andrew Geissler44fc3162020-07-09 09:21:31 -0500511{
512 auto pSRC = primarySRC();
513 if (!pSRC)
514 {
515 return false;
516 }
517
518 bool calloutPresent = false;
519 if ((*pSRC)->callouts())
520 {
521 for (auto& i : (*pSRC)->callouts()->callouts())
522 {
523 if (((*i).fruIdentity()))
524 {
525 auto& fruId = (*i).fruIdentity();
Andrew Geisslerf8e750d2022-01-14 14:56:13 -0600526 if ((*fruId).failingComponentType() ==
527 src::FRUIdentity::hardwareFRU)
Andrew Geissler44fc3162020-07-09 09:21:31 -0500528 {
529 calloutPresent = true;
530 break;
531 }
532 }
533 }
534 }
535
536 return calloutPresent;
537}
538
Sumit Kumar3160a542021-04-26 08:07:04 -0500539void PEL::updateSysInfoInExtendedUserDataSection(
540 const DataInterfaceBase& dataIface)
541{
542 const AdditionalData additionalData;
543
544 // Check for PEL from Hostboot
545 if (_ph->creatorID() == static_cast<uint8_t>(CreatorID::hostboot))
546 {
547 // Get the ED section from PEL
548 auto op = std::find_if(_optionalSections.begin(),
549 _optionalSections.end(), [](auto& section) {
550 return section->header().id ==
551 static_cast<uint16_t>(
552 SectionID::extUserData);
553 });
554
555 // Check for ED section found and its not the last section of PEL
556 if (op != _optionalSections.end())
557 {
558 // Get the extended user data class mapped to found section
559 auto extUserData = static_cast<ExtendedUserData*>(op->get());
560
561 // Check for the creator ID is for OpenBMC
562 if (extUserData->creatorID() ==
563 static_cast<uint8_t>(CreatorID::openBMC))
564 {
565 // Update subtype and component id
566 auto subType = static_cast<uint8_t>(UserDataFormat::json);
567 auto componentId =
568 static_cast<uint16_t>(ComponentID::phosphorLogging);
569
570 // Update system data to ED section
571 auto ud =
572 util::makeSysInfoUserDataSection(additionalData, dataIface);
573 extUserData->updateDataSection(subType, componentId,
574 ud->data());
575 }
576 }
577 }
578}
579
Sumit Kumar3e274432021-09-14 06:37:56 -0500580void PEL::updateTerminateBitInSRCSection()
581{
582 // Check for pel severity of type - 0x51 = critical error, system
583 // termination
584 if (_uh->severity() == 0x51)
585 {
586 // Get the primary SRC section
587 auto pSRC = primarySRC();
588 if (pSRC)
589 {
590 (*pSRC)->setTerminateBit();
591 }
592 }
593}
594
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600595namespace util
596{
597
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600598std::unique_ptr<UserData> makeJSONUserDataSection(const nlohmann::json& json)
599{
600 auto jsonString = json.dump();
601 std::vector<uint8_t> jsonData(jsonString.begin(), jsonString.end());
602
603 // Pad to a 4 byte boundary
604 while ((jsonData.size() % 4) != 0)
605 {
606 jsonData.push_back(0);
607 }
608
609 return std::make_unique<UserData>(
610 static_cast<uint16_t>(ComponentID::phosphorLogging),
611 static_cast<uint8_t>(UserDataFormat::json),
612 static_cast<uint8_t>(UserDataFormatVersion::json), jsonData);
613}
614
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600615std::unique_ptr<UserData> makeADUserDataSection(const AdditionalData& ad)
616{
617 assert(!ad.empty());
618 nlohmann::json json;
619
620 // Remove the 'ESEL' entry, as it contains a full PEL in the value.
621 if (ad.getValue("ESEL"))
622 {
623 auto newAD = ad;
624 newAD.remove("ESEL");
625 json = newAD.toJSON();
626 }
627 else
628 {
629 json = ad.toJSON();
630 }
631
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600632 return makeJSONUserDataSection(json);
633}
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600634
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600635void addProcessNameToJSON(nlohmann::json& json,
636 const std::optional<std::string>& pid,
637 const DataInterfaceBase& dataIface)
638{
Matt Spinler677381b2020-01-23 10:04:29 -0600639 std::string name{unknownValue};
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600640
641 try
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600642 {
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600643 if (pid)
644 {
645 auto n = dataIface.getProcessName(*pid);
646 if (n)
647 {
648 name = *n;
649 }
650 }
651 }
Patrick Williams66491c62021-10-06 12:23:37 -0500652 catch (const std::exception& e)
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600653 {
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600654 }
655
Sumit Kumar3160a542021-04-26 08:07:04 -0500656 if (pid)
657 {
658 json["Process Name"] = std::move(name);
659 }
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600660}
661
Matt Spinler677381b2020-01-23 10:04:29 -0600662void addBMCFWVersionIDToJSON(nlohmann::json& json,
663 const DataInterfaceBase& dataIface)
664{
665 auto id = dataIface.getBMCFWVersionID();
666 if (id.empty())
667 {
668 id = unknownValue;
669 }
670
Matt Spinlerc2b8a512021-05-21 12:44:42 -0600671 json["FW Version ID"] = std::move(id);
Matt Spinler677381b2020-01-23 10:04:29 -0600672}
673
Matt Spinler4aa23a12020-02-03 15:05:09 -0600674std::string lastSegment(char separator, std::string data)
675{
676 auto pos = data.find_last_of(separator);
677 if (pos != std::string::npos)
678 {
679 data = data.substr(pos + 1);
680 }
681
682 return data;
683}
684
Ben Tynere32b7e72021-05-18 12:38:40 -0500685void addIMKeyword(nlohmann::json& json, const DataInterfaceBase& dataIface)
686{
687 auto keyword = dataIface.getSystemIMKeyword();
688
689 std::string value{};
690
691 std::for_each(keyword.begin(), keyword.end(), [&](const auto& byte) {
692 value += fmt::format("{:02X}", byte);
693 });
694
695 json["System IM"] = value;
696}
697
Matt Spinler4aa23a12020-02-03 15:05:09 -0600698void addStatesToJSON(nlohmann::json& json, const DataInterfaceBase& dataIface)
699{
700 json["BMCState"] = lastSegment('.', dataIface.getBMCState());
701 json["ChassisState"] = lastSegment('.', dataIface.getChassisState());
702 json["HostState"] = lastSegment('.', dataIface.getHostState());
Sumit Kumar2c36fdd2021-09-21 03:12:11 -0500703 json["BootState"] = lastSegment('.', dataIface.getBootState());
Matt Spinler4aa23a12020-02-03 15:05:09 -0600704}
705
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600706std::unique_ptr<UserData>
707 makeSysInfoUserDataSection(const AdditionalData& ad,
708 const DataInterfaceBase& dataIface)
709{
710 nlohmann::json json;
711
712 addProcessNameToJSON(json, ad.getValue("_PID"), dataIface);
Matt Spinler677381b2020-01-23 10:04:29 -0600713 addBMCFWVersionIDToJSON(json, dataIface);
Ben Tynere32b7e72021-05-18 12:38:40 -0500714 addIMKeyword(json, dataIface);
Matt Spinler4aa23a12020-02-03 15:05:09 -0600715 addStatesToJSON(json, dataIface);
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600716
717 return makeJSONUserDataSection(json);
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600718}
719
Matt Spinler5b289b22020-03-26 14:27:19 -0500720std::vector<uint8_t> readFD(int fd)
721{
722 std::vector<uint8_t> data;
723
724 // Get the size
725 struct stat s;
726 int r = fstat(fd, &s);
727 if (r != 0)
728 {
729 auto e = errno;
730 log<level::ERR>("Could not get FFDC file size from FD",
731 entry("ERRNO=%d", e));
732 return data;
733 }
734
735 if (0 == s.st_size)
736 {
737 log<level::ERR>("FFDC file is empty");
738 return data;
739 }
740
741 data.resize(s.st_size);
742
743 // Make sure its at the beginning, as maybe another
744 // extension already used it.
745 r = lseek(fd, 0, SEEK_SET);
746 if (r == -1)
747 {
748 auto e = errno;
749 log<level::ERR>("Could not seek to beginning of FFDC file",
750 entry("ERRNO=%d", e));
751 return data;
752 }
753
754 r = read(fd, data.data(), s.st_size);
755 if (r == -1)
756 {
757 auto e = errno;
758 log<level::ERR>("Could not read FFDC file", entry("ERRNO=%d", e));
759 }
760 else if (r != s.st_size)
761 {
762 log<level::WARNING>("Could not read full FFDC file",
763 entry("FILE_SIZE=%d", s.st_size),
764 entry("SIZE_READ=%d", r));
765 }
766
767 return data;
768}
769
Matt Spinler56ad2a02020-03-26 14:00:52 -0500770std::unique_ptr<UserData> makeFFDCuserDataSection(uint16_t componentID,
771 const PelFFDCfile& file)
772{
Matt Spinler5b289b22020-03-26 14:27:19 -0500773 auto data = readFD(file.fd);
774
775 if (data.empty())
776 {
777 return std::unique_ptr<UserData>();
778 }
779
780 // The data needs 4 Byte alignment, and save amount padded for the
781 // CBOR case.
782 uint32_t pad = 0;
783 while (data.size() % 4)
784 {
785 data.push_back(0);
786 pad++;
787 }
788
789 // For JSON, CBOR, and Text use our component ID, subType, and version,
790 // otherwise use the supplied ones.
791 uint16_t compID = static_cast<uint16_t>(ComponentID::phosphorLogging);
792 uint8_t subType{};
793 uint8_t version{};
794
795 switch (file.format)
796 {
797 case UserDataFormat::json:
798 subType = static_cast<uint8_t>(UserDataFormat::json);
799 version = static_cast<uint8_t>(UserDataFormatVersion::json);
800 break;
801 case UserDataFormat::cbor:
802 subType = static_cast<uint8_t>(UserDataFormat::cbor);
803 version = static_cast<uint8_t>(UserDataFormatVersion::cbor);
804
805 // The CBOR parser will fail on the extra pad bytes since they
806 // aren't CBOR. Add the amount we padded to the end and other
807 // code will remove it all before parsing.
808 {
809 data.resize(data.size() + 4);
810 Stream stream{data};
811 stream.offset(data.size() - 4);
812 stream << pad;
813 }
814
815 break;
816 case UserDataFormat::text:
817 subType = static_cast<uint8_t>(UserDataFormat::text);
818 version = static_cast<uint8_t>(UserDataFormatVersion::text);
819 break;
820 case UserDataFormat::custom:
821 default:
822 // Use the passed in values
823 compID = componentID;
824 subType = file.subType;
825 version = file.version;
826 break;
827 }
828
829 return std::make_unique<UserData>(compID, subType, version, data);
Matt Spinler56ad2a02020-03-26 14:00:52 -0500830}
831
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600832} // namespace util
833
Matt Spinlercb6b0592019-07-16 15:58:51 -0500834} // namespace pels
835} // namespace openpower