blob: f1a73c4efbc57faf48e39fa2413f2560c673bfb2 [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 */
Matt Spinlercb6b0592019-07-16 15:58:51 -050016#include "pel.hpp"
17
18#include "bcd_time.hpp"
Matt Spinler386a61e2020-08-13 15:51:12 -050019#include "extended_user_data.hpp"
Matt Spinlerc63e2e82019-12-02 15:50:12 -060020#include "extended_user_header.hpp"
Matt Spinleraa659472019-10-23 09:26:48 -050021#include "failing_mtms.hpp"
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +080022#include "json_utils.hpp"
Matt Spinlercb6b0592019-07-16 15:58:51 -050023#include "log_id.hpp"
Matt Spinlerf1e85e22019-11-01 11:31:31 -050024#include "pel_rules.hpp"
Aatir186ce8c2019-10-20 15:13:39 -050025#include "pel_values.hpp"
Matt Spinler131870c2019-09-25 13:29:04 -050026#include "section_factory.hpp"
Matt Spinlerbd716f02019-10-15 10:54:11 -050027#include "src.hpp"
Matt Spinlercb6b0592019-07-16 15:58:51 -050028#include "stream.hpp"
Matt Spinlerafa857c2019-10-24 13:03:46 -050029#include "user_data_formats.hpp"
Matt Spinlercb6b0592019-07-16 15:58:51 -050030
Jayanth Othayothe8bdeea2021-06-03 03:01:16 -050031#ifdef SBE_FFDC_SUPPORTED
32#include "sbe_ffdc_handler.hpp"
33#endif
34
Ben Tynere32b7e72021-05-18 12:38:40 -050035#include <fmt/format.h>
Matt Spinler5b289b22020-03-26 14:27:19 -050036#include <sys/stat.h>
37#include <unistd.h>
38
Aatir186ce8c2019-10-20 15:13:39 -050039#include <iostream>
Matt Spinler07eefc52019-09-26 11:18:26 -050040#include <phosphor-logging/log.hpp>
41
Matt Spinlercb6b0592019-07-16 15:58:51 -050042namespace openpower
43{
44namespace pels
45{
Matt Spinlerb8323632019-09-20 15:11:04 -050046namespace message = openpower::pels::message;
Aatir186ce8c2019-10-20 15:13:39 -050047namespace pv = openpower::pels::pel_values;
Matt Spinler4bfc9082020-03-24 15:05:54 -050048using namespace phosphor::logging;
Matt Spinlerb8323632019-09-20 15:11:04 -050049
Matt Spinler677381b2020-01-23 10:04:29 -060050constexpr auto unknownValue = "Unknown";
Matt Spinler5a90a952020-08-27 09:39:03 -050051constexpr uint8_t jsonCalloutSubtype = 0xCA;
Matt Spinler677381b2020-01-23 10:04:29 -060052
Matt Spinler4bfc9082020-03-24 15:05:54 -050053PEL::PEL(const message::Entry& regEntry, uint32_t obmcLogID, uint64_t timestamp,
Matt Spinlerbd716f02019-10-15 10:54:11 -050054 phosphor::logging::Entry::Level severity,
Jayanth Othayothe8bdeea2021-06-03 03:01:16 -050055 const AdditionalData& additionalData, const PelFFDC& ffdcFilesIn,
Matt Spinleraa659472019-10-23 09:26:48 -050056 const DataInterfaceBase& dataIface)
Matt Spinlerb8323632019-09-20 15:11:04 -050057{
Jayanth Othayothe8bdeea2021-06-03 03:01:16 -050058 // No changes in input, for non SBE error related requests
59 PelFFDC ffdcFiles = ffdcFilesIn;
60
61#ifdef SBE_FFDC_SUPPORTED
62 // Add sbe ffdc processed data into ffdcfiles.
63 namespace sbe = openpower::pels::sbe;
64 auto processReq =
65 std::any_of(ffdcFiles.begin(), ffdcFiles.end(), [](const auto& file) {
66 return file.format == UserDataFormat::custom &&
67 file.subType == sbe::sbeFFDCSubType;
68 });
69 // sbeFFDC can't be destroyed until the end of the PEL constructor
70 // because it needs to keep around the FFDC Files to be used below.
71 std::unique_ptr<sbe::SbeFFDC> sbeFFDCPtr;
72 if (processReq)
73 {
74 sbeFFDCPtr =
75 std::make_unique<sbe::SbeFFDC>(additionalData, ffdcFilesIn);
76 const auto& sbeFFDCFiles = sbeFFDCPtr->getSbeFFDC();
77 ffdcFiles.insert(ffdcFiles.end(), sbeFFDCFiles.begin(),
78 sbeFFDCFiles.end());
79 }
80#endif
81
Matt Spinler85f61a62020-06-03 16:28:55 -050082 std::map<std::string, std::vector<std::string>> debugData;
Matt Spinler5a90a952020-08-27 09:39:03 -050083 nlohmann::json callouts;
Matt Spinler85f61a62020-06-03 16:28:55 -050084
Matt Spinler4bfc9082020-03-24 15:05:54 -050085 _ph = std::make_unique<PrivateHeader>(regEntry.componentID, obmcLogID,
Matt Spinlerb8323632019-09-20 15:11:04 -050086 timestamp);
Vijay Lobo6b3f3452021-04-15 23:04:42 -050087 _uh = std::make_unique<UserHeader>(regEntry, severity, additionalData,
88 dataIface);
Matt Spinlerb8323632019-09-20 15:11:04 -050089
Matt Spinler5a90a952020-08-27 09:39:03 -050090 // Extract any callouts embedded in an FFDC file.
91 if (!ffdcFiles.empty())
92 {
93 try
94 {
95 callouts = getCalloutJSON(ffdcFiles);
96 }
97 catch (const std::exception& e)
98 {
99 debugData.emplace("FFDC file JSON callouts error",
100 std::vector<std::string>{e.what()});
101 }
102 }
103
104 auto src =
105 std::make_unique<SRC>(regEntry, additionalData, callouts, dataIface);
106
Matt Spinler85f61a62020-06-03 16:28:55 -0500107 if (!src->getDebugData().empty())
108 {
109 // Something didn't go as planned
110 debugData.emplace("SRC", src->getDebugData());
111 }
Matt Spinlerc63e2e82019-12-02 15:50:12 -0600112
Matt Spinler4bfc9082020-03-24 15:05:54 -0500113 auto euh = std::make_unique<ExtendedUserHeader>(dataIface, regEntry, *src);
Matt Spinlerc63e2e82019-12-02 15:50:12 -0600114
Matt Spinlerbd716f02019-10-15 10:54:11 -0500115 _optionalSections.push_back(std::move(src));
Matt Spinlerc63e2e82019-12-02 15:50:12 -0600116 _optionalSections.push_back(std::move(euh));
Matt Spinlerb8323632019-09-20 15:11:04 -0500117
Matt Spinleraa659472019-10-23 09:26:48 -0500118 auto mtms = std::make_unique<FailingMTMS>(dataIface);
119 _optionalSections.push_back(std::move(mtms));
Matt Spinlerbd716f02019-10-15 10:54:11 -0500120
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600121 auto ud = util::makeSysInfoUserDataSection(additionalData, dataIface);
Matt Spinler85f61a62020-06-03 16:28:55 -0500122 addUserDataSection(std::move(ud));
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600123
Matt Spinler9b7e94f2020-03-24 15:44:41 -0500124 // Create a UserData section from AdditionalData.
Matt Spinlerafa857c2019-10-24 13:03:46 -0500125 if (!additionalData.empty())
126 {
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600127 ud = util::makeADUserDataSection(additionalData);
Matt Spinler85f61a62020-06-03 16:28:55 -0500128 addUserDataSection(std::move(ud));
Matt Spinlerafa857c2019-10-24 13:03:46 -0500129 }
130
Matt Spinler56ad2a02020-03-26 14:00:52 -0500131 // Add any FFDC files into UserData sections
132 for (const auto& file : ffdcFiles)
133 {
134 ud = util::makeFFDCuserDataSection(regEntry.componentID, file);
135 if (!ud)
136 {
Matt Spinler85f61a62020-06-03 16:28:55 -0500137 // Add this error into the debug data UserData section
138 std::ostringstream msg;
139 msg << "Could not make PEL FFDC UserData section from file"
140 << std::hex << regEntry.componentID << " " << file.subType
141 << " " << file.version;
142 if (debugData.count("FFDC File"))
143 {
144 debugData.at("FFDC File").push_back(msg.str());
145 }
146 else
147 {
148 debugData.emplace("FFDC File",
149 std::vector<std::string>{msg.str()});
150 }
151
Matt Spinler56ad2a02020-03-26 14:00:52 -0500152 continue;
153 }
154
Matt Spinler85f61a62020-06-03 16:28:55 -0500155 addUserDataSection(std::move(ud));
156 }
Matt Spinler56ad2a02020-03-26 14:00:52 -0500157
Matt Spinler85f61a62020-06-03 16:28:55 -0500158 // Store in the PEL any important debug data created while
159 // building the PEL sections.
160 if (!debugData.empty())
161 {
162 nlohmann::json data;
163 data["PEL Internal Debug Data"] = debugData;
164 ud = util::makeJSONUserDataSection(data);
165
166 addUserDataSection(std::move(ud));
167
168 // Also put in the journal for debug
169 for (const auto& [name, data] : debugData)
170 {
171 for (const auto& message : data)
172 {
173 std::string entry = name + ": " + message;
174 log<level::INFO>(entry.c_str());
Matt Spinler56ad2a02020-03-26 14:00:52 -0500175 }
176 }
Matt Spinler56ad2a02020-03-26 14:00:52 -0500177 }
178
Matt Spinler97d19b42019-10-29 11:34:03 -0500179 _ph->setSectionCount(2 + _optionalSections.size());
Matt Spinlerf1e85e22019-11-01 11:31:31 -0500180
181 checkRulesAndFix();
Matt Spinlerb8323632019-09-20 15:11:04 -0500182}
Matt Spinlercb6b0592019-07-16 15:58:51 -0500183
Matt Spinler07eefc52019-09-26 11:18:26 -0500184PEL::PEL(std::vector<uint8_t>& data) : PEL(data, 0)
Matt Spinlercb6b0592019-07-16 15:58:51 -0500185{
186}
187
Matt Spinler07eefc52019-09-26 11:18:26 -0500188PEL::PEL(std::vector<uint8_t>& data, uint32_t obmcLogID)
Matt Spinlercb6b0592019-07-16 15:58:51 -0500189{
Matt Spinler07eefc52019-09-26 11:18:26 -0500190 populateFromRawData(data, obmcLogID);
Matt Spinlercb6b0592019-07-16 15:58:51 -0500191}
192
Matt Spinler07eefc52019-09-26 11:18:26 -0500193void PEL::populateFromRawData(std::vector<uint8_t>& data, uint32_t obmcLogID)
Matt Spinlercb6b0592019-07-16 15:58:51 -0500194{
Matt Spinler07eefc52019-09-26 11:18:26 -0500195 Stream pelData{data};
Matt Spinlercb6b0592019-07-16 15:58:51 -0500196 _ph = std::make_unique<PrivateHeader>(pelData);
197 if (obmcLogID != 0)
198 {
Matt Spinler97d19b42019-10-29 11:34:03 -0500199 _ph->setOBMCLogID(obmcLogID);
Matt Spinlercb6b0592019-07-16 15:58:51 -0500200 }
201
202 _uh = std::make_unique<UserHeader>(pelData);
Matt Spinler131870c2019-09-25 13:29:04 -0500203
204 // Use the section factory to create the rest of the objects
205 for (size_t i = 2; i < _ph->sectionCount(); i++)
206 {
207 auto section = section_factory::create(pelData);
208 _optionalSections.push_back(std::move(section));
209 }
Matt Spinlercb6b0592019-07-16 15:58:51 -0500210}
211
212bool PEL::valid() const
213{
214 bool valid = _ph->valid();
215
216 if (valid)
217 {
218 valid = _uh->valid();
219 }
220
Matt Spinler131870c2019-09-25 13:29:04 -0500221 if (valid)
222 {
223 if (!std::all_of(_optionalSections.begin(), _optionalSections.end(),
224 [](const auto& section) { return section->valid(); }))
225 {
226 valid = false;
227 }
228 }
229
Matt Spinlercb6b0592019-07-16 15:58:51 -0500230 return valid;
231}
232
233void PEL::setCommitTime()
234{
235 auto now = std::chrono::system_clock::now();
Matt Spinler97d19b42019-10-29 11:34:03 -0500236 _ph->setCommitTimestamp(getBCDTime(now));
Matt Spinlercb6b0592019-07-16 15:58:51 -0500237}
238
239void PEL::assignID()
240{
Matt Spinler97d19b42019-10-29 11:34:03 -0500241 _ph->setID(generatePELID());
Matt Spinlercb6b0592019-07-16 15:58:51 -0500242}
243
Matt Spinler06885452019-11-06 10:35:42 -0600244void PEL::flatten(std::vector<uint8_t>& pelBuffer) const
Matt Spinlercb6b0592019-07-16 15:58:51 -0500245{
246 Stream pelData{pelBuffer};
Matt Spinlerb8323632019-09-20 15:11:04 -0500247
Matt Spinler07eefc52019-09-26 11:18:26 -0500248 if (!valid())
Matt Spinlercb6b0592019-07-16 15:58:51 -0500249 {
Matt Spinler07eefc52019-09-26 11:18:26 -0500250 log<level::WARNING>("Unflattening an invalid PEL");
Matt Spinlercb6b0592019-07-16 15:58:51 -0500251 }
252
Matt Spinler07eefc52019-09-26 11:18:26 -0500253 _ph->flatten(pelData);
Matt Spinlerb8323632019-09-20 15:11:04 -0500254 _uh->flatten(pelData);
Matt Spinler07eefc52019-09-26 11:18:26 -0500255
256 for (auto& section : _optionalSections)
257 {
258 section->flatten(pelData);
259 }
Matt Spinlercb6b0592019-07-16 15:58:51 -0500260}
261
Matt Spinler06885452019-11-06 10:35:42 -0600262std::vector<uint8_t> PEL::data() const
Matt Spinlercb6b0592019-07-16 15:58:51 -0500263{
Matt Spinler07eefc52019-09-26 11:18:26 -0500264 std::vector<uint8_t> pelData;
265 flatten(pelData);
266 return pelData;
Matt Spinlercb6b0592019-07-16 15:58:51 -0500267}
268
Matt Spinlerf1b46ff2020-01-22 14:10:04 -0600269size_t PEL::size() const
270{
271 size_t size = 0;
272
273 if (_ph)
274 {
275 size += _ph->header().size;
276 }
277
278 if (_uh)
279 {
280 size += _uh->header().size;
281 }
282
283 for (const auto& section : _optionalSections)
284 {
285 size += section->header().size;
286 }
287
288 return size;
289}
290
Matt Spinlerbd716f02019-10-15 10:54:11 -0500291std::optional<SRC*> PEL::primarySRC() const
292{
293 auto src = std::find_if(
294 _optionalSections.begin(), _optionalSections.end(), [](auto& section) {
295 return section->header().id ==
296 static_cast<uint16_t>(SectionID::primarySRC);
297 });
298 if (src != _optionalSections.end())
299 {
300 return static_cast<SRC*>(src->get());
301 }
302
303 return std::nullopt;
304}
305
Matt Spinlerf1e85e22019-11-01 11:31:31 -0500306void PEL::checkRulesAndFix()
307{
Matt Spinler1f93c592020-09-10 10:43:08 -0500308 // Only fix if the action flags are at their default value which
309 // means they weren't specified in the registry. Otherwise
310 // assume the user knows what they are doing.
311 if (_uh->actionFlags() == actionFlagsDefault)
312 {
313 auto [actionFlags, eventType] =
314 pel_rules::check(0, _uh->eventType(), _uh->severity());
Matt Spinlerf1e85e22019-11-01 11:31:31 -0500315
Matt Spinler1f93c592020-09-10 10:43:08 -0500316 _uh->setActionFlags(actionFlags);
317 _uh->setEventType(eventType);
318 }
Matt Spinlerf1e85e22019-11-01 11:31:31 -0500319}
320
Matt Spinleracb7c102020-01-10 13:49:22 -0600321void PEL::printSectionInJSON(const Section& section, std::string& buf,
Harisuddin Mohamed Isaa214ed32020-02-28 15:58:23 +0800322 std::map<uint16_t, size_t>& pluralSections,
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800323 message::Registry& registry,
324 const std::vector<std::string>& plugins,
325 uint8_t creatorID) const
Aatir186ce8c2019-10-20 15:13:39 -0500326{
327 char tmpB[5];
Aatir Manzurad0e0472019-10-07 13:18:37 -0500328 uint8_t id[] = {static_cast<uint8_t>(section.header().id >> 8),
329 static_cast<uint8_t>(section.header().id)};
330 sprintf(tmpB, "%c%c", id[0], id[1]);
331 std::string sectionID(tmpB);
332 std::string sectionName = pv::sectionTitles.count(sectionID)
333 ? pv::sectionTitles.at(sectionID)
334 : "Unknown Section";
Matt Spinleracb7c102020-01-10 13:49:22 -0600335
336 // Add a count if there are multiple of this type of section
337 auto count = pluralSections.find(section.header().id);
338 if (count != pluralSections.end())
339 {
340 sectionName += " " + std::to_string(count->second);
341 count->second++;
342 }
343
Aatir186ce8c2019-10-20 15:13:39 -0500344 if (section.valid())
345 {
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800346 std::optional<std::string> json;
347 if (sectionID == "PS" || sectionID == "SS")
348 {
Harisuddin Mohamed Isac8d6cc62020-08-19 22:47:19 +0800349 json = section.getJSON(registry, plugins, creatorID);
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800350 }
Matt Spinler386a61e2020-08-13 15:51:12 -0500351 else if ((sectionID == "UD") || (sectionID == "ED"))
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800352 {
Harisuddin Mohamed Isa3fdcd4e2020-08-26 11:56:42 +0800353 json = section.getJSON(creatorID, plugins);
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800354 }
355 else
356 {
357 json = section.getJSON();
358 }
Matt Spinler4220a152020-03-26 10:18:09 -0500359
360 buf += "\"" + sectionName + "\": {\n";
361
Aatir Manzurad0e0472019-10-07 13:18:37 -0500362 if (json)
363 {
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800364 buf += *json + "\n},\n";
Aatir Manzurad0e0472019-10-07 13:18:37 -0500365 }
366 else
367 {
Matt Spinler4220a152020-03-26 10:18:09 -0500368 jsonInsert(buf, pv::sectionVer,
369 getNumberString("%d", section.header().version), 1);
370 jsonInsert(buf, pv::subSection,
371 getNumberString("%d", section.header().subType), 1);
372 jsonInsert(buf, pv::createdBy,
373 getNumberString("0x%X", section.header().componentID),
374 1);
375
Aatir Manzurad0e0472019-10-07 13:18:37 -0500376 std::vector<uint8_t> data;
377 Stream s{data};
378 section.flatten(s);
Matt Spinler4220a152020-03-26 10:18:09 -0500379 std::string dstr =
380 dumpHex(std::data(data) + SectionHeader::flattenedSize(),
Harisuddin Mohamed Isa097ad122020-06-11 21:19:41 +0800381 data.size() - SectionHeader::flattenedSize(), 2);
Matt Spinler4220a152020-03-26 10:18:09 -0500382 std::string jsonIndent(indentLevel, 0x20);
383 buf += jsonIndent + "\"Data\": [\n";
384 buf += dstr;
385 buf += jsonIndent + "]\n";
386 buf += "},\n";
Aatir Manzurad0e0472019-10-07 13:18:37 -0500387 }
Aatir186ce8c2019-10-20 15:13:39 -0500388 }
389 else
390 {
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800391 buf += "\n\"Invalid Section\": [\n \"invalid\"\n],\n";
Aatir186ce8c2019-10-20 15:13:39 -0500392 }
393}
394
Matt Spinleracb7c102020-01-10 13:49:22 -0600395std::map<uint16_t, size_t> PEL::getPluralSections() const
396{
397 std::map<uint16_t, size_t> sectionCounts;
398
399 for (const auto& section : optionalSections())
400 {
401 if (sectionCounts.find(section->header().id) == sectionCounts.end())
402 {
403 sectionCounts[section->header().id] = 1;
404 }
405 else
406 {
407 sectionCounts[section->header().id]++;
408 }
409 }
410
411 std::map<uint16_t, size_t> sections;
412 for (const auto& [id, count] : sectionCounts)
413 {
414 if (count > 1)
415 {
416 // Start with 0 here and printSectionInJSON()
417 // will increment it as it goes.
418 sections.emplace(id, 0);
419 }
420 }
421
422 return sections;
423}
424
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800425void PEL::toJSON(message::Registry& registry,
426 const std::vector<std::string>& plugins) const
Aatir186ce8c2019-10-20 15:13:39 -0500427{
Matt Spinleracb7c102020-01-10 13:49:22 -0600428 auto sections = getPluralSections();
429
Harisuddin Mohamed Isaa214ed32020-02-28 15:58:23 +0800430 std::string buf = "{\n";
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800431 printSectionInJSON(*(_ph.get()), buf, sections, registry, plugins);
432 printSectionInJSON(*(_uh.get()), buf, sections, registry, plugins);
Aatir186ce8c2019-10-20 15:13:39 -0500433 for (auto& section : this->optionalSections())
434 {
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800435 printSectionInJSON(*(section.get()), buf, sections, registry, plugins,
436 _ph->creatorID());
Aatir186ce8c2019-10-20 15:13:39 -0500437 }
438 buf += "}";
439 std::size_t found = buf.rfind(",");
440 if (found != std::string::npos)
441 buf.replace(found, 1, "");
442 std::cout << buf << std::endl;
443}
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800444
Matt Spinler85f61a62020-06-03 16:28:55 -0500445bool PEL::addUserDataSection(std::unique_ptr<UserData> userData)
446{
447 if (size() + userData->header().size > _maxPELSize)
448 {
449 if (userData->shrink(_maxPELSize - size()))
450 {
451 _optionalSections.push_back(std::move(userData));
452 }
453 else
454 {
455 log<level::WARNING>(
456 "Could not shrink UserData section. Dropping",
457 entry("SECTION_SIZE=%d\n", userData->header().size),
458 entry("COMPONENT_ID=0x%02X", userData->header().componentID),
459 entry("SUBTYPE=0x%X", userData->header().subType),
460 entry("VERSION=0x%X", userData->header().version));
461 return false;
462 }
463 }
464 else
465 {
466 _optionalSections.push_back(std::move(userData));
467 }
468 return true;
469}
470
Matt Spinler5a90a952020-08-27 09:39:03 -0500471nlohmann::json PEL::getCalloutJSON(const PelFFDC& ffdcFiles)
472{
473 nlohmann::json callouts;
474
475 for (const auto& file : ffdcFiles)
476 {
477 if ((file.format == UserDataFormat::json) &&
478 (file.subType == jsonCalloutSubtype))
479 {
480 auto data = util::readFD(file.fd);
481 if (data.empty())
482 {
483 throw std::runtime_error{
484 "Could not get data from JSON callout file descriptor"};
485 }
486
487 std::string jsonString{data.begin(), data.begin() + data.size()};
488
489 callouts = nlohmann::json::parse(jsonString);
490 break;
491 }
492 }
493
494 return callouts;
495}
496
Andrew Geissler44fc3162020-07-09 09:21:31 -0500497bool PEL::isCalloutPresent() const
498{
499 auto pSRC = primarySRC();
500 if (!pSRC)
501 {
502 return false;
503 }
504
505 bool calloutPresent = false;
506 if ((*pSRC)->callouts())
507 {
508 for (auto& i : (*pSRC)->callouts()->callouts())
509 {
510 if (((*i).fruIdentity()))
511 {
512 auto& fruId = (*i).fruIdentity();
513 if ((*fruId).failingComponentType() != 0)
514 {
515 calloutPresent = true;
516 break;
517 }
518 }
519 }
520 }
521
522 return calloutPresent;
523}
524
Sumit Kumar3160a542021-04-26 08:07:04 -0500525void PEL::updateSysInfoInExtendedUserDataSection(
526 const DataInterfaceBase& dataIface)
527{
528 const AdditionalData additionalData;
529
530 // Check for PEL from Hostboot
531 if (_ph->creatorID() == static_cast<uint8_t>(CreatorID::hostboot))
532 {
533 // Get the ED section from PEL
534 auto op = std::find_if(_optionalSections.begin(),
535 _optionalSections.end(), [](auto& section) {
536 return section->header().id ==
537 static_cast<uint16_t>(
538 SectionID::extUserData);
539 });
540
541 // Check for ED section found and its not the last section of PEL
542 if (op != _optionalSections.end())
543 {
544 // Get the extended user data class mapped to found section
545 auto extUserData = static_cast<ExtendedUserData*>(op->get());
546
547 // Check for the creator ID is for OpenBMC
548 if (extUserData->creatorID() ==
549 static_cast<uint8_t>(CreatorID::openBMC))
550 {
551 // Update subtype and component id
552 auto subType = static_cast<uint8_t>(UserDataFormat::json);
553 auto componentId =
554 static_cast<uint16_t>(ComponentID::phosphorLogging);
555
556 // Update system data to ED section
557 auto ud =
558 util::makeSysInfoUserDataSection(additionalData, dataIface);
559 extUserData->updateDataSection(subType, componentId,
560 ud->data());
561 }
562 }
563 }
564}
565
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600566namespace util
567{
568
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600569std::unique_ptr<UserData> makeJSONUserDataSection(const nlohmann::json& json)
570{
571 auto jsonString = json.dump();
572 std::vector<uint8_t> jsonData(jsonString.begin(), jsonString.end());
573
574 // Pad to a 4 byte boundary
575 while ((jsonData.size() % 4) != 0)
576 {
577 jsonData.push_back(0);
578 }
579
580 return std::make_unique<UserData>(
581 static_cast<uint16_t>(ComponentID::phosphorLogging),
582 static_cast<uint8_t>(UserDataFormat::json),
583 static_cast<uint8_t>(UserDataFormatVersion::json), jsonData);
584}
585
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600586std::unique_ptr<UserData> makeADUserDataSection(const AdditionalData& ad)
587{
588 assert(!ad.empty());
589 nlohmann::json json;
590
591 // Remove the 'ESEL' entry, as it contains a full PEL in the value.
592 if (ad.getValue("ESEL"))
593 {
594 auto newAD = ad;
595 newAD.remove("ESEL");
596 json = newAD.toJSON();
597 }
598 else
599 {
600 json = ad.toJSON();
601 }
602
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600603 return makeJSONUserDataSection(json);
604}
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600605
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600606void addProcessNameToJSON(nlohmann::json& json,
607 const std::optional<std::string>& pid,
608 const DataInterfaceBase& dataIface)
609{
Matt Spinler677381b2020-01-23 10:04:29 -0600610 std::string name{unknownValue};
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600611
612 try
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600613 {
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600614 if (pid)
615 {
616 auto n = dataIface.getProcessName(*pid);
617 if (n)
618 {
619 name = *n;
620 }
621 }
622 }
623 catch (std::exception& e)
624 {
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600625 }
626
Sumit Kumar3160a542021-04-26 08:07:04 -0500627 if (pid)
628 {
629 json["Process Name"] = std::move(name);
630 }
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600631}
632
Matt Spinler677381b2020-01-23 10:04:29 -0600633void addBMCFWVersionIDToJSON(nlohmann::json& json,
634 const DataInterfaceBase& dataIface)
635{
636 auto id = dataIface.getBMCFWVersionID();
637 if (id.empty())
638 {
639 id = unknownValue;
640 }
641
Matt Spinlerc2b8a512021-05-21 12:44:42 -0600642 json["FW Version ID"] = std::move(id);
Matt Spinler677381b2020-01-23 10:04:29 -0600643}
644
Matt Spinler4aa23a12020-02-03 15:05:09 -0600645std::string lastSegment(char separator, std::string data)
646{
647 auto pos = data.find_last_of(separator);
648 if (pos != std::string::npos)
649 {
650 data = data.substr(pos + 1);
651 }
652
653 return data;
654}
655
Ben Tynere32b7e72021-05-18 12:38:40 -0500656void addIMKeyword(nlohmann::json& json, const DataInterfaceBase& dataIface)
657{
658 auto keyword = dataIface.getSystemIMKeyword();
659
660 std::string value{};
661
662 std::for_each(keyword.begin(), keyword.end(), [&](const auto& byte) {
663 value += fmt::format("{:02X}", byte);
664 });
665
666 json["System IM"] = value;
667}
668
Matt Spinler4aa23a12020-02-03 15:05:09 -0600669void addStatesToJSON(nlohmann::json& json, const DataInterfaceBase& dataIface)
670{
671 json["BMCState"] = lastSegment('.', dataIface.getBMCState());
672 json["ChassisState"] = lastSegment('.', dataIface.getChassisState());
673 json["HostState"] = lastSegment('.', dataIface.getHostState());
674}
675
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600676std::unique_ptr<UserData>
677 makeSysInfoUserDataSection(const AdditionalData& ad,
678 const DataInterfaceBase& dataIface)
679{
680 nlohmann::json json;
681
682 addProcessNameToJSON(json, ad.getValue("_PID"), dataIface);
Matt Spinler677381b2020-01-23 10:04:29 -0600683 addBMCFWVersionIDToJSON(json, dataIface);
Ben Tynere32b7e72021-05-18 12:38:40 -0500684 addIMKeyword(json, dataIface);
Matt Spinler4aa23a12020-02-03 15:05:09 -0600685 addStatesToJSON(json, dataIface);
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600686
687 return makeJSONUserDataSection(json);
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600688}
689
Matt Spinler5b289b22020-03-26 14:27:19 -0500690std::vector<uint8_t> readFD(int fd)
691{
692 std::vector<uint8_t> data;
693
694 // Get the size
695 struct stat s;
696 int r = fstat(fd, &s);
697 if (r != 0)
698 {
699 auto e = errno;
700 log<level::ERR>("Could not get FFDC file size from FD",
701 entry("ERRNO=%d", e));
702 return data;
703 }
704
705 if (0 == s.st_size)
706 {
707 log<level::ERR>("FFDC file is empty");
708 return data;
709 }
710
711 data.resize(s.st_size);
712
713 // Make sure its at the beginning, as maybe another
714 // extension already used it.
715 r = lseek(fd, 0, SEEK_SET);
716 if (r == -1)
717 {
718 auto e = errno;
719 log<level::ERR>("Could not seek to beginning of FFDC file",
720 entry("ERRNO=%d", e));
721 return data;
722 }
723
724 r = read(fd, data.data(), s.st_size);
725 if (r == -1)
726 {
727 auto e = errno;
728 log<level::ERR>("Could not read FFDC file", entry("ERRNO=%d", e));
729 }
730 else if (r != s.st_size)
731 {
732 log<level::WARNING>("Could not read full FFDC file",
733 entry("FILE_SIZE=%d", s.st_size),
734 entry("SIZE_READ=%d", r));
735 }
736
737 return data;
738}
739
Matt Spinler56ad2a02020-03-26 14:00:52 -0500740std::unique_ptr<UserData> makeFFDCuserDataSection(uint16_t componentID,
741 const PelFFDCfile& file)
742{
Matt Spinler5b289b22020-03-26 14:27:19 -0500743 auto data = readFD(file.fd);
744
745 if (data.empty())
746 {
747 return std::unique_ptr<UserData>();
748 }
749
750 // The data needs 4 Byte alignment, and save amount padded for the
751 // CBOR case.
752 uint32_t pad = 0;
753 while (data.size() % 4)
754 {
755 data.push_back(0);
756 pad++;
757 }
758
759 // For JSON, CBOR, and Text use our component ID, subType, and version,
760 // otherwise use the supplied ones.
761 uint16_t compID = static_cast<uint16_t>(ComponentID::phosphorLogging);
762 uint8_t subType{};
763 uint8_t version{};
764
765 switch (file.format)
766 {
767 case UserDataFormat::json:
768 subType = static_cast<uint8_t>(UserDataFormat::json);
769 version = static_cast<uint8_t>(UserDataFormatVersion::json);
770 break;
771 case UserDataFormat::cbor:
772 subType = static_cast<uint8_t>(UserDataFormat::cbor);
773 version = static_cast<uint8_t>(UserDataFormatVersion::cbor);
774
775 // The CBOR parser will fail on the extra pad bytes since they
776 // aren't CBOR. Add the amount we padded to the end and other
777 // code will remove it all before parsing.
778 {
779 data.resize(data.size() + 4);
780 Stream stream{data};
781 stream.offset(data.size() - 4);
782 stream << pad;
783 }
784
785 break;
786 case UserDataFormat::text:
787 subType = static_cast<uint8_t>(UserDataFormat::text);
788 version = static_cast<uint8_t>(UserDataFormatVersion::text);
789 break;
790 case UserDataFormat::custom:
791 default:
792 // Use the passed in values
793 compID = componentID;
794 subType = file.subType;
795 version = file.version;
796 break;
797 }
798
799 return std::make_unique<UserData>(compID, subType, version, data);
Matt Spinler56ad2a02020-03-26 14:00:52 -0500800}
801
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600802} // namespace util
803
Matt Spinlercb6b0592019-07-16 15:58:51 -0500804} // namespace pels
805} // namespace openpower