blob: 3de2fa32bb45ab8d83e4e26883e6c1cefbef5139 [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{
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());
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
112 auto src =
113 std::make_unique<SRC>(regEntry, additionalData, callouts, dataIface);
114
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 {
191 std::string entry = name + ": " + message;
192 log<level::INFO>(entry.c_str());
Matt Spinler56ad2a02020-03-26 14:00:52 -0500193 }
194 }
Matt Spinler56ad2a02020-03-26 14:00:52 -0500195 }
196
Matt Spinler97d19b42019-10-29 11:34:03 -0500197 _ph->setSectionCount(2 + _optionalSections.size());
Matt Spinlerf1e85e22019-11-01 11:31:31 -0500198
199 checkRulesAndFix();
Matt Spinlerb8323632019-09-20 15:11:04 -0500200}
Matt Spinlercb6b0592019-07-16 15:58:51 -0500201
Matt Spinler07eefc52019-09-26 11:18:26 -0500202PEL::PEL(std::vector<uint8_t>& data) : PEL(data, 0)
Matt Spinlercb6b0592019-07-16 15:58:51 -0500203{
204}
205
Matt Spinler07eefc52019-09-26 11:18:26 -0500206PEL::PEL(std::vector<uint8_t>& data, uint32_t obmcLogID)
Matt Spinlercb6b0592019-07-16 15:58:51 -0500207{
Matt Spinler07eefc52019-09-26 11:18:26 -0500208 populateFromRawData(data, obmcLogID);
Matt Spinlercb6b0592019-07-16 15:58:51 -0500209}
210
Matt Spinler07eefc52019-09-26 11:18:26 -0500211void PEL::populateFromRawData(std::vector<uint8_t>& data, uint32_t obmcLogID)
Matt Spinlercb6b0592019-07-16 15:58:51 -0500212{
Matt Spinler07eefc52019-09-26 11:18:26 -0500213 Stream pelData{data};
Matt Spinlercb6b0592019-07-16 15:58:51 -0500214 _ph = std::make_unique<PrivateHeader>(pelData);
215 if (obmcLogID != 0)
216 {
Matt Spinler97d19b42019-10-29 11:34:03 -0500217 _ph->setOBMCLogID(obmcLogID);
Matt Spinlercb6b0592019-07-16 15:58:51 -0500218 }
219
220 _uh = std::make_unique<UserHeader>(pelData);
Matt Spinler131870c2019-09-25 13:29:04 -0500221
222 // Use the section factory to create the rest of the objects
223 for (size_t i = 2; i < _ph->sectionCount(); i++)
224 {
225 auto section = section_factory::create(pelData);
226 _optionalSections.push_back(std::move(section));
227 }
Matt Spinlercb6b0592019-07-16 15:58:51 -0500228}
229
230bool PEL::valid() const
231{
232 bool valid = _ph->valid();
233
234 if (valid)
235 {
236 valid = _uh->valid();
237 }
238
Matt Spinler131870c2019-09-25 13:29:04 -0500239 if (valid)
240 {
241 if (!std::all_of(_optionalSections.begin(), _optionalSections.end(),
242 [](const auto& section) { return section->valid(); }))
243 {
244 valid = false;
245 }
246 }
247
Matt Spinlercb6b0592019-07-16 15:58:51 -0500248 return valid;
249}
250
251void PEL::setCommitTime()
252{
253 auto now = std::chrono::system_clock::now();
Matt Spinler97d19b42019-10-29 11:34:03 -0500254 _ph->setCommitTimestamp(getBCDTime(now));
Matt Spinlercb6b0592019-07-16 15:58:51 -0500255}
256
257void PEL::assignID()
258{
Matt Spinler97d19b42019-10-29 11:34:03 -0500259 _ph->setID(generatePELID());
Matt Spinlercb6b0592019-07-16 15:58:51 -0500260}
261
Matt Spinler06885452019-11-06 10:35:42 -0600262void PEL::flatten(std::vector<uint8_t>& pelBuffer) const
Matt Spinlercb6b0592019-07-16 15:58:51 -0500263{
264 Stream pelData{pelBuffer};
Matt Spinlerb8323632019-09-20 15:11:04 -0500265
Matt Spinler07eefc52019-09-26 11:18:26 -0500266 if (!valid())
Matt Spinlercb6b0592019-07-16 15:58:51 -0500267 {
Matt Spinler07eefc52019-09-26 11:18:26 -0500268 log<level::WARNING>("Unflattening an invalid PEL");
Matt Spinlercb6b0592019-07-16 15:58:51 -0500269 }
270
Matt Spinler07eefc52019-09-26 11:18:26 -0500271 _ph->flatten(pelData);
Matt Spinlerb8323632019-09-20 15:11:04 -0500272 _uh->flatten(pelData);
Matt Spinler07eefc52019-09-26 11:18:26 -0500273
274 for (auto& section : _optionalSections)
275 {
276 section->flatten(pelData);
277 }
Matt Spinlercb6b0592019-07-16 15:58:51 -0500278}
279
Matt Spinler06885452019-11-06 10:35:42 -0600280std::vector<uint8_t> PEL::data() const
Matt Spinlercb6b0592019-07-16 15:58:51 -0500281{
Matt Spinler07eefc52019-09-26 11:18:26 -0500282 std::vector<uint8_t> pelData;
283 flatten(pelData);
284 return pelData;
Matt Spinlercb6b0592019-07-16 15:58:51 -0500285}
286
Matt Spinlerf1b46ff2020-01-22 14:10:04 -0600287size_t PEL::size() const
288{
289 size_t size = 0;
290
291 if (_ph)
292 {
293 size += _ph->header().size;
294 }
295
296 if (_uh)
297 {
298 size += _uh->header().size;
299 }
300
301 for (const auto& section : _optionalSections)
302 {
303 size += section->header().size;
304 }
305
306 return size;
307}
308
Matt Spinlerbd716f02019-10-15 10:54:11 -0500309std::optional<SRC*> PEL::primarySRC() const
310{
311 auto src = std::find_if(
312 _optionalSections.begin(), _optionalSections.end(), [](auto& section) {
313 return section->header().id ==
314 static_cast<uint16_t>(SectionID::primarySRC);
315 });
316 if (src != _optionalSections.end())
317 {
318 return static_cast<SRC*>(src->get());
319 }
320
321 return std::nullopt;
322}
323
Matt Spinlerf1e85e22019-11-01 11:31:31 -0500324void PEL::checkRulesAndFix()
325{
Matt Spinler1f93c592020-09-10 10:43:08 -0500326 // Only fix if the action flags are at their default value which
327 // means they weren't specified in the registry. Otherwise
328 // assume the user knows what they are doing.
329 if (_uh->actionFlags() == actionFlagsDefault)
330 {
331 auto [actionFlags, eventType] =
332 pel_rules::check(0, _uh->eventType(), _uh->severity());
Matt Spinlerf1e85e22019-11-01 11:31:31 -0500333
Matt Spinler1f93c592020-09-10 10:43:08 -0500334 _uh->setActionFlags(actionFlags);
335 _uh->setEventType(eventType);
336 }
Matt Spinlerf1e85e22019-11-01 11:31:31 -0500337}
338
Matt Spinleracb7c102020-01-10 13:49:22 -0600339void PEL::printSectionInJSON(const Section& section, std::string& buf,
Harisuddin Mohamed Isaa214ed32020-02-28 15:58:23 +0800340 std::map<uint16_t, size_t>& pluralSections,
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800341 message::Registry& registry,
342 const std::vector<std::string>& plugins,
343 uint8_t creatorID) const
Aatir186ce8c2019-10-20 15:13:39 -0500344{
345 char tmpB[5];
Aatir Manzurad0e0472019-10-07 13:18:37 -0500346 uint8_t id[] = {static_cast<uint8_t>(section.header().id >> 8),
347 static_cast<uint8_t>(section.header().id)};
348 sprintf(tmpB, "%c%c", id[0], id[1]);
349 std::string sectionID(tmpB);
350 std::string sectionName = pv::sectionTitles.count(sectionID)
351 ? pv::sectionTitles.at(sectionID)
352 : "Unknown Section";
Matt Spinleracb7c102020-01-10 13:49:22 -0600353
354 // Add a count if there are multiple of this type of section
355 auto count = pluralSections.find(section.header().id);
356 if (count != pluralSections.end())
357 {
358 sectionName += " " + std::to_string(count->second);
359 count->second++;
360 }
361
Aatir186ce8c2019-10-20 15:13:39 -0500362 if (section.valid())
363 {
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800364 std::optional<std::string> json;
365 if (sectionID == "PS" || sectionID == "SS")
366 {
Harisuddin Mohamed Isac8d6cc62020-08-19 22:47:19 +0800367 json = section.getJSON(registry, plugins, creatorID);
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800368 }
Matt Spinler386a61e2020-08-13 15:51:12 -0500369 else if ((sectionID == "UD") || (sectionID == "ED"))
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800370 {
Harisuddin Mohamed Isa3fdcd4e2020-08-26 11:56:42 +0800371 json = section.getJSON(creatorID, plugins);
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800372 }
373 else
374 {
375 json = section.getJSON();
376 }
Matt Spinler4220a152020-03-26 10:18:09 -0500377
378 buf += "\"" + sectionName + "\": {\n";
379
Aatir Manzurad0e0472019-10-07 13:18:37 -0500380 if (json)
381 {
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800382 buf += *json + "\n},\n";
Aatir Manzurad0e0472019-10-07 13:18:37 -0500383 }
384 else
385 {
Matt Spinler4220a152020-03-26 10:18:09 -0500386 jsonInsert(buf, pv::sectionVer,
387 getNumberString("%d", section.header().version), 1);
388 jsonInsert(buf, pv::subSection,
389 getNumberString("%d", section.header().subType), 1);
390 jsonInsert(buf, pv::createdBy,
391 getNumberString("0x%X", section.header().componentID),
392 1);
393
Aatir Manzurad0e0472019-10-07 13:18:37 -0500394 std::vector<uint8_t> data;
395 Stream s{data};
396 section.flatten(s);
Matt Spinler4220a152020-03-26 10:18:09 -0500397 std::string dstr =
398 dumpHex(std::data(data) + SectionHeader::flattenedSize(),
Harisuddin Mohamed Isa097ad122020-06-11 21:19:41 +0800399 data.size() - SectionHeader::flattenedSize(), 2);
Matt Spinler4220a152020-03-26 10:18:09 -0500400 std::string jsonIndent(indentLevel, 0x20);
401 buf += jsonIndent + "\"Data\": [\n";
402 buf += dstr;
403 buf += jsonIndent + "]\n";
404 buf += "},\n";
Aatir Manzurad0e0472019-10-07 13:18:37 -0500405 }
Aatir186ce8c2019-10-20 15:13:39 -0500406 }
407 else
408 {
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800409 buf += "\n\"Invalid Section\": [\n \"invalid\"\n],\n";
Aatir186ce8c2019-10-20 15:13:39 -0500410 }
411}
412
Matt Spinleracb7c102020-01-10 13:49:22 -0600413std::map<uint16_t, size_t> PEL::getPluralSections() const
414{
415 std::map<uint16_t, size_t> sectionCounts;
416
417 for (const auto& section : optionalSections())
418 {
419 if (sectionCounts.find(section->header().id) == sectionCounts.end())
420 {
421 sectionCounts[section->header().id] = 1;
422 }
423 else
424 {
425 sectionCounts[section->header().id]++;
426 }
427 }
428
429 std::map<uint16_t, size_t> sections;
430 for (const auto& [id, count] : sectionCounts)
431 {
432 if (count > 1)
433 {
434 // Start with 0 here and printSectionInJSON()
435 // will increment it as it goes.
436 sections.emplace(id, 0);
437 }
438 }
439
440 return sections;
441}
442
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800443void PEL::toJSON(message::Registry& registry,
444 const std::vector<std::string>& plugins) const
Aatir186ce8c2019-10-20 15:13:39 -0500445{
Matt Spinleracb7c102020-01-10 13:49:22 -0600446 auto sections = getPluralSections();
447
Harisuddin Mohamed Isaa214ed32020-02-28 15:58:23 +0800448 std::string buf = "{\n";
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800449 printSectionInJSON(*(_ph.get()), buf, sections, registry, plugins);
450 printSectionInJSON(*(_uh.get()), buf, sections, registry, plugins);
Aatir186ce8c2019-10-20 15:13:39 -0500451 for (auto& section : this->optionalSections())
452 {
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800453 printSectionInJSON(*(section.get()), buf, sections, registry, plugins,
454 _ph->creatorID());
Aatir186ce8c2019-10-20 15:13:39 -0500455 }
456 buf += "}";
457 std::size_t found = buf.rfind(",");
458 if (found != std::string::npos)
459 buf.replace(found, 1, "");
460 std::cout << buf << std::endl;
461}
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800462
Matt Spinler85f61a62020-06-03 16:28:55 -0500463bool PEL::addUserDataSection(std::unique_ptr<UserData> userData)
464{
465 if (size() + userData->header().size > _maxPELSize)
466 {
467 if (userData->shrink(_maxPELSize - size()))
468 {
469 _optionalSections.push_back(std::move(userData));
470 }
471 else
472 {
473 log<level::WARNING>(
474 "Could not shrink UserData section. Dropping",
475 entry("SECTION_SIZE=%d\n", userData->header().size),
476 entry("COMPONENT_ID=0x%02X", userData->header().componentID),
477 entry("SUBTYPE=0x%X", userData->header().subType),
478 entry("VERSION=0x%X", userData->header().version));
479 return false;
480 }
481 }
482 else
483 {
484 _optionalSections.push_back(std::move(userData));
485 }
486 return true;
487}
488
Matt Spinler5a90a952020-08-27 09:39:03 -0500489nlohmann::json PEL::getCalloutJSON(const PelFFDC& ffdcFiles)
490{
491 nlohmann::json callouts;
492
493 for (const auto& file : ffdcFiles)
494 {
495 if ((file.format == UserDataFormat::json) &&
496 (file.subType == jsonCalloutSubtype))
497 {
498 auto data = util::readFD(file.fd);
499 if (data.empty())
500 {
501 throw std::runtime_error{
502 "Could not get data from JSON callout file descriptor"};
503 }
504
505 std::string jsonString{data.begin(), data.begin() + data.size()};
506
507 callouts = nlohmann::json::parse(jsonString);
508 break;
509 }
510 }
511
512 return callouts;
513}
514
Andrew Geisslerf8e750d2022-01-14 14:56:13 -0600515bool PEL::isHwCalloutPresent() const
Andrew Geissler44fc3162020-07-09 09:21:31 -0500516{
517 auto pSRC = primarySRC();
518 if (!pSRC)
519 {
520 return false;
521 }
522
523 bool calloutPresent = false;
524 if ((*pSRC)->callouts())
525 {
526 for (auto& i : (*pSRC)->callouts()->callouts())
527 {
528 if (((*i).fruIdentity()))
529 {
530 auto& fruId = (*i).fruIdentity();
Andrew Geisslerf8e750d2022-01-14 14:56:13 -0600531 if ((*fruId).failingComponentType() ==
532 src::FRUIdentity::hardwareFRU)
Andrew Geissler44fc3162020-07-09 09:21:31 -0500533 {
534 calloutPresent = true;
535 break;
536 }
537 }
538 }
539 }
540
541 return calloutPresent;
542}
543
Sumit Kumar3160a542021-04-26 08:07:04 -0500544void PEL::updateSysInfoInExtendedUserDataSection(
545 const DataInterfaceBase& dataIface)
546{
547 const AdditionalData additionalData;
548
549 // Check for PEL from Hostboot
550 if (_ph->creatorID() == static_cast<uint8_t>(CreatorID::hostboot))
551 {
552 // Get the ED section from PEL
553 auto op = std::find_if(_optionalSections.begin(),
554 _optionalSections.end(), [](auto& section) {
555 return section->header().id ==
556 static_cast<uint16_t>(
557 SectionID::extUserData);
558 });
559
560 // Check for ED section found and its not the last section of PEL
561 if (op != _optionalSections.end())
562 {
563 // Get the extended user data class mapped to found section
564 auto extUserData = static_cast<ExtendedUserData*>(op->get());
565
566 // Check for the creator ID is for OpenBMC
567 if (extUserData->creatorID() ==
568 static_cast<uint8_t>(CreatorID::openBMC))
569 {
570 // Update subtype and component id
571 auto subType = static_cast<uint8_t>(UserDataFormat::json);
572 auto componentId =
573 static_cast<uint16_t>(ComponentID::phosphorLogging);
574
575 // Update system data to ED section
George Liu9ac0d9b2022-07-15 10:57:38 +0800576 auto ud = util::makeSysInfoUserDataSection(additionalData,
577 dataIface, false);
Sumit Kumar3160a542021-04-26 08:07:04 -0500578 extUserData->updateDataSection(subType, componentId,
579 ud->data());
580 }
581 }
582 }
583}
584
Sumit Kumar3e274432021-09-14 06:37:56 -0500585void PEL::updateTerminateBitInSRCSection()
586{
587 // Check for pel severity of type - 0x51 = critical error, system
588 // termination
589 if (_uh->severity() == 0x51)
590 {
591 // Get the primary SRC section
592 auto pSRC = primarySRC();
593 if (pSRC)
594 {
595 (*pSRC)->setTerminateBit();
596 }
597 }
598}
599
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600600namespace util
601{
602
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600603std::unique_ptr<UserData> makeJSONUserDataSection(const nlohmann::json& json)
604{
605 auto jsonString = json.dump();
606 std::vector<uint8_t> jsonData(jsonString.begin(), jsonString.end());
607
608 // Pad to a 4 byte boundary
609 while ((jsonData.size() % 4) != 0)
610 {
611 jsonData.push_back(0);
612 }
613
614 return std::make_unique<UserData>(
615 static_cast<uint16_t>(ComponentID::phosphorLogging),
616 static_cast<uint8_t>(UserDataFormat::json),
617 static_cast<uint8_t>(UserDataFormatVersion::json), jsonData);
618}
619
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600620std::unique_ptr<UserData> makeADUserDataSection(const AdditionalData& ad)
621{
622 assert(!ad.empty());
623 nlohmann::json json;
624
625 // Remove the 'ESEL' entry, as it contains a full PEL in the value.
626 if (ad.getValue("ESEL"))
627 {
628 auto newAD = ad;
629 newAD.remove("ESEL");
630 json = newAD.toJSON();
631 }
632 else
633 {
634 json = ad.toJSON();
635 }
636
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600637 return makeJSONUserDataSection(json);
638}
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600639
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600640void addProcessNameToJSON(nlohmann::json& json,
641 const std::optional<std::string>& pid,
642 const DataInterfaceBase& dataIface)
643{
Matt Spinler677381b2020-01-23 10:04:29 -0600644 std::string name{unknownValue};
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600645
646 try
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600647 {
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600648 if (pid)
649 {
650 auto n = dataIface.getProcessName(*pid);
651 if (n)
652 {
653 name = *n;
654 }
655 }
656 }
Patrick Williams66491c62021-10-06 12:23:37 -0500657 catch (const std::exception& e)
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600658 {
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600659 }
660
Sumit Kumar3160a542021-04-26 08:07:04 -0500661 if (pid)
662 {
663 json["Process Name"] = std::move(name);
664 }
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600665}
666
Matt Spinler677381b2020-01-23 10:04:29 -0600667void addBMCFWVersionIDToJSON(nlohmann::json& json,
668 const DataInterfaceBase& dataIface)
669{
670 auto id = dataIface.getBMCFWVersionID();
671 if (id.empty())
672 {
673 id = unknownValue;
674 }
675
Matt Spinlerc2b8a512021-05-21 12:44:42 -0600676 json["FW Version ID"] = std::move(id);
Matt Spinler677381b2020-01-23 10:04:29 -0600677}
678
Matt Spinler4aa23a12020-02-03 15:05:09 -0600679std::string lastSegment(char separator, std::string data)
680{
681 auto pos = data.find_last_of(separator);
682 if (pos != std::string::npos)
683 {
684 data = data.substr(pos + 1);
685 }
686
687 return data;
688}
689
Ben Tynere32b7e72021-05-18 12:38:40 -0500690void addIMKeyword(nlohmann::json& json, const DataInterfaceBase& dataIface)
691{
692 auto keyword = dataIface.getSystemIMKeyword();
693
694 std::string value{};
695
696 std::for_each(keyword.begin(), keyword.end(), [&](const auto& byte) {
697 value += fmt::format("{:02X}", byte);
698 });
699
700 json["System IM"] = value;
701}
702
Matt Spinler4aa23a12020-02-03 15:05:09 -0600703void addStatesToJSON(nlohmann::json& json, const DataInterfaceBase& dataIface)
704{
705 json["BMCState"] = lastSegment('.', dataIface.getBMCState());
706 json["ChassisState"] = lastSegment('.', dataIface.getChassisState());
707 json["HostState"] = lastSegment('.', dataIface.getHostState());
Sumit Kumar2c36fdd2021-09-21 03:12:11 -0500708 json["BootState"] = lastSegment('.', dataIface.getBootState());
Matt Spinler4aa23a12020-02-03 15:05:09 -0600709}
710
George Liu9ac0d9b2022-07-15 10:57:38 +0800711void addBMCUptime(nlohmann::json& json, const DataInterfaceBase& dataIface)
712{
713 auto seconds = dataIface.getUptimeInSeconds();
714 if (seconds)
715 {
716 json["BMCUptime"] = dataIface.getBMCUptime(*seconds);
717 }
718 else
719 {
720 json["BMCUptime"] = "";
721 }
722 json["BMCLoad"] = dataIface.getBMCLoadAvg();
723}
724
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600725std::unique_ptr<UserData>
726 makeSysInfoUserDataSection(const AdditionalData& ad,
George Liu9ac0d9b2022-07-15 10:57:38 +0800727 const DataInterfaceBase& dataIface,
728 bool addUptime)
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600729{
730 nlohmann::json json;
731
732 addProcessNameToJSON(json, ad.getValue("_PID"), dataIface);
Matt Spinler677381b2020-01-23 10:04:29 -0600733 addBMCFWVersionIDToJSON(json, dataIface);
Ben Tynere32b7e72021-05-18 12:38:40 -0500734 addIMKeyword(json, dataIface);
Matt Spinler4aa23a12020-02-03 15:05:09 -0600735 addStatesToJSON(json, dataIface);
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600736
George Liu9ac0d9b2022-07-15 10:57:38 +0800737 if (addUptime)
738 {
739 addBMCUptime(json, dataIface);
740 }
741
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600742 return makeJSONUserDataSection(json);
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600743}
744
Matt Spinler5b289b22020-03-26 14:27:19 -0500745std::vector<uint8_t> readFD(int fd)
746{
747 std::vector<uint8_t> data;
748
749 // Get the size
750 struct stat s;
751 int r = fstat(fd, &s);
752 if (r != 0)
753 {
754 auto e = errno;
755 log<level::ERR>("Could not get FFDC file size from FD",
756 entry("ERRNO=%d", e));
757 return data;
758 }
759
760 if (0 == s.st_size)
761 {
762 log<level::ERR>("FFDC file is empty");
763 return data;
764 }
765
766 data.resize(s.st_size);
767
768 // Make sure its at the beginning, as maybe another
769 // extension already used it.
770 r = lseek(fd, 0, SEEK_SET);
771 if (r == -1)
772 {
773 auto e = errno;
774 log<level::ERR>("Could not seek to beginning of FFDC file",
775 entry("ERRNO=%d", e));
776 return data;
777 }
778
779 r = read(fd, data.data(), s.st_size);
780 if (r == -1)
781 {
782 auto e = errno;
783 log<level::ERR>("Could not read FFDC file", entry("ERRNO=%d", e));
784 }
785 else if (r != s.st_size)
786 {
787 log<level::WARNING>("Could not read full FFDC file",
788 entry("FILE_SIZE=%d", s.st_size),
789 entry("SIZE_READ=%d", r));
790 }
791
792 return data;
793}
794
Matt Spinler56ad2a02020-03-26 14:00:52 -0500795std::unique_ptr<UserData> makeFFDCuserDataSection(uint16_t componentID,
796 const PelFFDCfile& file)
797{
Matt Spinler5b289b22020-03-26 14:27:19 -0500798 auto data = readFD(file.fd);
799
800 if (data.empty())
801 {
802 return std::unique_ptr<UserData>();
803 }
804
805 // The data needs 4 Byte alignment, and save amount padded for the
806 // CBOR case.
807 uint32_t pad = 0;
808 while (data.size() % 4)
809 {
810 data.push_back(0);
811 pad++;
812 }
813
814 // For JSON, CBOR, and Text use our component ID, subType, and version,
815 // otherwise use the supplied ones.
816 uint16_t compID = static_cast<uint16_t>(ComponentID::phosphorLogging);
817 uint8_t subType{};
818 uint8_t version{};
819
820 switch (file.format)
821 {
822 case UserDataFormat::json:
823 subType = static_cast<uint8_t>(UserDataFormat::json);
824 version = static_cast<uint8_t>(UserDataFormatVersion::json);
825 break;
826 case UserDataFormat::cbor:
827 subType = static_cast<uint8_t>(UserDataFormat::cbor);
828 version = static_cast<uint8_t>(UserDataFormatVersion::cbor);
829
830 // The CBOR parser will fail on the extra pad bytes since they
831 // aren't CBOR. Add the amount we padded to the end and other
832 // code will remove it all before parsing.
833 {
834 data.resize(data.size() + 4);
835 Stream stream{data};
836 stream.offset(data.size() - 4);
837 stream << pad;
838 }
839
840 break;
841 case UserDataFormat::text:
842 subType = static_cast<uint8_t>(UserDataFormat::text);
843 version = static_cast<uint8_t>(UserDataFormatVersion::text);
844 break;
845 case UserDataFormat::custom:
846 default:
847 // Use the passed in values
848 compID = componentID;
849 subType = file.subType;
850 version = file.version;
851 break;
852 }
853
854 return std::make_unique<UserData>(compID, subType, version, data);
Matt Spinler56ad2a02020-03-26 14:00:52 -0500855}
856
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600857} // namespace util
858
Matt Spinlercb6b0592019-07-16 15:58:51 -0500859} // namespace pels
860} // namespace openpower