1711d51d8SMatt Spinler /**
2711d51d8SMatt Spinler * Copyright © 2019 IBM Corporation
3711d51d8SMatt Spinler *
4711d51d8SMatt Spinler * Licensed under the Apache License, Version 2.0 (the "License");
5711d51d8SMatt Spinler * you may not use this file except in compliance with the License.
6711d51d8SMatt Spinler * You may obtain a copy of the License at
7711d51d8SMatt Spinler *
8711d51d8SMatt Spinler * http://www.apache.org/licenses/LICENSE-2.0
9711d51d8SMatt Spinler *
10711d51d8SMatt Spinler * Unless required by applicable law or agreed to in writing, software
11711d51d8SMatt Spinler * distributed under the License is distributed on an "AS IS" BASIS,
12711d51d8SMatt Spinler * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13711d51d8SMatt Spinler * See the License for the specific language governing permissions and
14711d51d8SMatt Spinler * limitations under the License.
15711d51d8SMatt Spinler */
16da9b5833SJayanth Othayoth #include "config.h"
17da9b5833SJayanth Othayoth
18cb6b059eSMatt Spinler #include "pel.hpp"
19cb6b059eSMatt Spinler
20cb6b059eSMatt Spinler #include "bcd_time.hpp"
21386a61e6SMatt Spinler #include "extended_user_data.hpp"
22c63e2e82SMatt Spinler #include "extended_user_header.hpp"
23aa659477SMatt Spinler #include "failing_mtms.hpp"
24f8e750ddSAndrew Geissler #include "fru_identity.hpp"
25600d15afSHarisuddin Mohamed Isa #include "json_utils.hpp"
26cb6b059eSMatt Spinler #include "log_id.hpp"
27f1e85e20SMatt Spinler #include "pel_rules.hpp"
28186ce8c9SAatir #include "pel_values.hpp"
29131870c7SMatt Spinler #include "section_factory.hpp"
30bd716f00SMatt Spinler #include "src.hpp"
31cb6b059eSMatt Spinler #include "stream.hpp"
32afa857c7SMatt Spinler #include "user_data_formats.hpp"
33cb6b059eSMatt Spinler
3492b2066fSJayanth Othayoth #ifdef PEL_ENABLE_PHAL
35da9b5833SJayanth Othayoth #include "phal_service_actions.hpp"
36e8bdeeaaSJayanth Othayoth #include "sbe_ffdc_handler.hpp"
37ff35be3eSDeepa Karthikeyan
38ff35be3eSDeepa Karthikeyan #include <libguard/guard_interface.hpp>
39ff35be3eSDeepa Karthikeyan #include <libguard/include/guard_record.hpp>
40ff35be3eSDeepa Karthikeyan
41ff35be3eSDeepa Karthikeyan namespace libguard = openpower::guard;
42e8bdeeaaSJayanth Othayoth #endif
43e8bdeeaaSJayanth Othayoth
445b289b23SMatt Spinler #include <sys/stat.h>
455b289b23SMatt Spinler #include <unistd.h>
465b289b23SMatt Spinler
47fd2da660SMatt Spinler #include <phosphor-logging/lg2.hpp>
4807eefc54SMatt Spinler
491aa90d49SJayanth Othayoth #include <format>
502544b419SPatrick Williams #include <iostream>
51d8ae618aSArya K Padman #include <ranges>
522544b419SPatrick Williams
53cb6b059eSMatt Spinler namespace openpower
54cb6b059eSMatt Spinler {
55cb6b059eSMatt Spinler namespace pels
56cb6b059eSMatt Spinler {
57186ce8c9SAatir namespace pv = openpower::pels::pel_values;
58b832363dSMatt Spinler
59677381b8SMatt Spinler constexpr auto unknownValue = "Unknown";
60d8ae618aSArya K Padman constexpr auto AdDIMMInfoFetchError = "DIMMs Info Fetch Error";
61677381b8SMatt Spinler
PEL(const message::Entry & regEntry,uint32_t obmcLogID,uint64_t timestamp,phosphor::logging::Entry::Level severity,const AdditionalData & additionalData,const PelFFDC & ffdcFilesIn,const DataInterfaceBase & dataIface,const JournalBase & journal)624bfc908fSMatt Spinler PEL::PEL(const message::Entry& regEntry, uint32_t obmcLogID, uint64_t timestamp,
63bd716f00SMatt Spinler phosphor::logging::Entry::Level severity,
64e8bdeeaaSJayanth Othayoth const AdditionalData& additionalData, const PelFFDC& ffdcFilesIn,
659d921096SMatt Spinler const DataInterfaceBase& dataIface, const JournalBase& journal)
66b832363dSMatt Spinler {
67e8bdeeaaSJayanth Othayoth // No changes in input, for non SBE error related requests
68e8bdeeaaSJayanth Othayoth PelFFDC ffdcFiles = ffdcFilesIn;
69e8bdeeaaSJayanth Othayoth
7092b2066fSJayanth Othayoth #ifdef PEL_ENABLE_PHAL
71e8bdeeaaSJayanth Othayoth // Add sbe ffdc processed data into ffdcfiles.
72e8bdeeaaSJayanth Othayoth namespace sbe = openpower::pels::sbe;
73075c7923SPatrick Williams auto processReq =
74075c7923SPatrick Williams std::any_of(ffdcFiles.begin(), ffdcFiles.end(), [](const auto& file) {
75e8bdeeaaSJayanth Othayoth return file.format == UserDataFormat::custom &&
76e8bdeeaaSJayanth Othayoth file.subType == sbe::sbeFFDCSubType;
77e8bdeeaaSJayanth Othayoth });
78e8bdeeaaSJayanth Othayoth // sbeFFDC can't be destroyed until the end of the PEL constructor
79e8bdeeaaSJayanth Othayoth // because it needs to keep around the FFDC Files to be used below.
80e8bdeeaaSJayanth Othayoth std::unique_ptr<sbe::SbeFFDC> sbeFFDCPtr;
81e8bdeeaaSJayanth Othayoth if (processReq)
82e8bdeeaaSJayanth Othayoth {
83075c7923SPatrick Williams sbeFFDCPtr =
84075c7923SPatrick Williams std::make_unique<sbe::SbeFFDC>(additionalData, ffdcFilesIn);
85e8bdeeaaSJayanth Othayoth const auto& sbeFFDCFiles = sbeFFDCPtr->getSbeFFDC();
86e8bdeeaaSJayanth Othayoth ffdcFiles.insert(ffdcFiles.end(), sbeFFDCFiles.begin(),
87e8bdeeaaSJayanth Othayoth sbeFFDCFiles.end());
88742b00b9SJayanth Othayoth
89742b00b9SJayanth Othayoth // update pel priority for spare clock failures
90742b00b9SJayanth Othayoth if (auto customSeverity = sbeFFDCPtr->getSeverity())
91742b00b9SJayanth Othayoth {
92742b00b9SJayanth Othayoth severity = customSeverity.value();
93742b00b9SJayanth Othayoth }
94e8bdeeaaSJayanth Othayoth }
95e8bdeeaaSJayanth Othayoth #endif
96e8bdeeaaSJayanth Othayoth
97d8ae618aSArya K Padman DebugData debugData;
985a90a95bSMatt Spinler nlohmann::json callouts;
9985f61a63SMatt Spinler
1004bfc908fSMatt Spinler _ph = std::make_unique<PrivateHeader>(regEntry.componentID, obmcLogID,
101b832363dSMatt Spinler timestamp);
1026b3f345bSVijay Lobo _uh = std::make_unique<UserHeader>(regEntry, severity, additionalData,
1036b3f345bSVijay Lobo dataIface);
104b832363dSMatt Spinler
1055a90a95bSMatt Spinler // Extract any callouts embedded in an FFDC file.
1065a90a95bSMatt Spinler if (!ffdcFiles.empty())
1075a90a95bSMatt Spinler {
1085a90a95bSMatt Spinler try
1095a90a95bSMatt Spinler {
1105a90a95bSMatt Spinler callouts = getCalloutJSON(ffdcFiles);
1115a90a95bSMatt Spinler }
1125a90a95bSMatt Spinler catch (const std::exception& e)
1135a90a95bSMatt Spinler {
1145a90a95bSMatt Spinler debugData.emplace("FFDC file JSON callouts error",
1155a90a95bSMatt Spinler std::vector<std::string>{e.what()});
1165a90a95bSMatt Spinler }
1175a90a95bSMatt Spinler }
1185a90a95bSMatt Spinler
119075c7923SPatrick Williams auto src =
120075c7923SPatrick Williams std::make_unique<SRC>(regEntry, additionalData, callouts, dataIface);
1215a90a95bSMatt Spinler
122d8ae618aSArya K Padman nlohmann::json adSysInfoData(nlohmann::json::value_t::object);
123d8ae618aSArya K Padman addAdDetailsForDIMMsCallout(src, dataIface, adSysInfoData, debugData);
124d8ae618aSArya K Padman
12585f61a63SMatt Spinler if (!src->getDebugData().empty())
12685f61a63SMatt Spinler {
12785f61a63SMatt Spinler // Something didn't go as planned
12885f61a63SMatt Spinler debugData.emplace("SRC", src->getDebugData());
12985f61a63SMatt Spinler }
130c63e2e82SMatt Spinler
1314bfc908fSMatt Spinler auto euh = std::make_unique<ExtendedUserHeader>(dataIface, regEntry, *src);
132c63e2e82SMatt Spinler
133bd716f00SMatt Spinler _optionalSections.push_back(std::move(src));
134c63e2e82SMatt Spinler _optionalSections.push_back(std::move(euh));
135b832363dSMatt Spinler
136aa659477SMatt Spinler auto mtms = std::make_unique<FailingMTMS>(dataIface);
137aa659477SMatt Spinler _optionalSections.push_back(std::move(mtms));
138bd716f00SMatt Spinler
139d8ae618aSArya K Padman auto ud = util::makeSysInfoUserDataSection(additionalData, dataIface, true,
140d8ae618aSArya K Padman adSysInfoData);
14185f61a63SMatt Spinler addUserDataSection(std::move(ud));
1424dcd3f46SMatt Spinler
1433e274432SSumit Kumar // Check for pel severity of type - 0x51 = critical error, system
1443e274432SSumit Kumar // termination and update terminate bit in SRC for pels
1453e274432SSumit Kumar updateTerminateBitInSRCSection();
1463e274432SSumit Kumar
1479b7e94ffSMatt Spinler // Create a UserData section from AdditionalData.
148afa857c7SMatt Spinler if (!additionalData.empty())
149afa857c7SMatt Spinler {
1504dcd3f46SMatt Spinler ud = util::makeADUserDataSection(additionalData);
15185f61a63SMatt Spinler addUserDataSection(std::move(ud));
1526d663820SMatt Spinler }
153afa857c7SMatt Spinler
15456ad2a0eSMatt Spinler // Add any FFDC files into UserData sections
15556ad2a0eSMatt Spinler for (const auto& file : ffdcFiles)
15656ad2a0eSMatt Spinler {
15756ad2a0eSMatt Spinler ud = util::makeFFDCuserDataSection(regEntry.componentID, file);
15856ad2a0eSMatt Spinler if (!ud)
15956ad2a0eSMatt Spinler {
16085f61a63SMatt Spinler // Add this error into the debug data UserData section
16185f61a63SMatt Spinler std::ostringstream msg;
16285f61a63SMatt Spinler msg << "Could not make PEL FFDC UserData section from file"
16385f61a63SMatt Spinler << std::hex << regEntry.componentID << " " << file.subType
16485f61a63SMatt Spinler << " " << file.version;
16585f61a63SMatt Spinler if (debugData.count("FFDC File"))
16685f61a63SMatt Spinler {
16785f61a63SMatt Spinler debugData.at("FFDC File").push_back(msg.str());
16885f61a63SMatt Spinler }
16985f61a63SMatt Spinler else
17085f61a63SMatt Spinler {
17185f61a63SMatt Spinler debugData.emplace("FFDC File",
17285f61a63SMatt Spinler std::vector<std::string>{msg.str()});
17385f61a63SMatt Spinler }
17485f61a63SMatt Spinler
17556ad2a0eSMatt Spinler continue;
17656ad2a0eSMatt Spinler }
17756ad2a0eSMatt Spinler
17885f61a63SMatt Spinler addUserDataSection(std::move(ud));
17956ad2a0eSMatt Spinler }
18056ad2a0eSMatt Spinler
181da9b5833SJayanth Othayoth #ifdef PEL_ENABLE_PHAL
182da9b5833SJayanth Othayoth auto path = std::string(OBJ_ENTRY) + '/' + std::to_string(obmcLogID);
183ff35be3eSDeepa Karthikeyan openpower::pels::phal::createServiceActions(callouts, dataIface, plid());
184da9b5833SJayanth Othayoth #endif
185da9b5833SJayanth Othayoth
18685f61a63SMatt Spinler // Store in the PEL any important debug data created while
18785f61a63SMatt Spinler // building the PEL sections.
18885f61a63SMatt Spinler if (!debugData.empty())
18985f61a63SMatt Spinler {
19085f61a63SMatt Spinler nlohmann::json data;
19185f61a63SMatt Spinler data["PEL Internal Debug Data"] = debugData;
19285f61a63SMatt Spinler ud = util::makeJSONUserDataSection(data);
19385f61a63SMatt Spinler
19485f61a63SMatt Spinler addUserDataSection(std::move(ud));
19585f61a63SMatt Spinler
19685f61a63SMatt Spinler // Also put in the journal for debug
19745796e82SMatt Spinler for (const auto& [name, msgs] : debugData)
19885f61a63SMatt Spinler {
19945796e82SMatt Spinler for (const auto& message : msgs)
20085f61a63SMatt Spinler {
201fd2da660SMatt Spinler lg2::info("{NAME}: {MSG}", "NAME", name, "MSG", message);
20285f61a63SMatt Spinler }
20385f61a63SMatt Spinler }
20456ad2a0eSMatt Spinler }
20556ad2a0eSMatt Spinler
2069d921096SMatt Spinler addJournalSections(regEntry, journal);
2079d921096SMatt Spinler
20897d19b48SMatt Spinler _ph->setSectionCount(2 + _optionalSections.size());
209f1e85e20SMatt Spinler
210f1e85e20SMatt Spinler checkRulesAndFix();
211b832363dSMatt Spinler }
212cb6b059eSMatt Spinler
PEL(std::vector<uint8_t> & data)2132544b419SPatrick Williams PEL::PEL(std::vector<uint8_t>& data) : PEL(data, 0) {}
214cb6b059eSMatt Spinler
PEL(std::vector<uint8_t> & data,uint32_t obmcLogID)21507eefc54SMatt Spinler PEL::PEL(std::vector<uint8_t>& data, uint32_t obmcLogID)
216cb6b059eSMatt Spinler {
21707eefc54SMatt Spinler populateFromRawData(data, obmcLogID);
218cb6b059eSMatt Spinler }
219cb6b059eSMatt Spinler
populateFromRawData(std::vector<uint8_t> & data,uint32_t obmcLogID)22007eefc54SMatt Spinler void PEL::populateFromRawData(std::vector<uint8_t>& data, uint32_t obmcLogID)
221cb6b059eSMatt Spinler {
22207eefc54SMatt Spinler Stream pelData{data};
223cb6b059eSMatt Spinler _ph = std::make_unique<PrivateHeader>(pelData);
224cb6b059eSMatt Spinler if (obmcLogID != 0)
225cb6b059eSMatt Spinler {
22697d19b48SMatt Spinler _ph->setOBMCLogID(obmcLogID);
227cb6b059eSMatt Spinler }
228cb6b059eSMatt Spinler
229cb6b059eSMatt Spinler _uh = std::make_unique<UserHeader>(pelData);
230131870c7SMatt Spinler
231131870c7SMatt Spinler // Use the section factory to create the rest of the objects
232131870c7SMatt Spinler for (size_t i = 2; i < _ph->sectionCount(); i++)
233131870c7SMatt Spinler {
234131870c7SMatt Spinler auto section = section_factory::create(pelData);
235131870c7SMatt Spinler _optionalSections.push_back(std::move(section));
236131870c7SMatt Spinler }
237cb6b059eSMatt Spinler }
238cb6b059eSMatt Spinler
valid() const239cb6b059eSMatt Spinler bool PEL::valid() const
240cb6b059eSMatt Spinler {
241cb6b059eSMatt Spinler bool valid = _ph->valid();
242cb6b059eSMatt Spinler
243cb6b059eSMatt Spinler if (valid)
244cb6b059eSMatt Spinler {
245cb6b059eSMatt Spinler valid = _uh->valid();
246cb6b059eSMatt Spinler }
247cb6b059eSMatt Spinler
248131870c7SMatt Spinler if (valid)
249131870c7SMatt Spinler {
250131870c7SMatt Spinler if (!std::all_of(_optionalSections.begin(), _optionalSections.end(),
251131870c7SMatt Spinler [](const auto& section) { return section->valid(); }))
252131870c7SMatt Spinler {
253131870c7SMatt Spinler valid = false;
254131870c7SMatt Spinler }
255131870c7SMatt Spinler }
256131870c7SMatt Spinler
257cb6b059eSMatt Spinler return valid;
258cb6b059eSMatt Spinler }
259cb6b059eSMatt Spinler
setCommitTime()260cb6b059eSMatt Spinler void PEL::setCommitTime()
261cb6b059eSMatt Spinler {
262cb6b059eSMatt Spinler auto now = std::chrono::system_clock::now();
26397d19b48SMatt Spinler _ph->setCommitTimestamp(getBCDTime(now));
264cb6b059eSMatt Spinler }
265cb6b059eSMatt Spinler
assignID()266cb6b059eSMatt Spinler void PEL::assignID()
267cb6b059eSMatt Spinler {
26897d19b48SMatt Spinler _ph->setID(generatePELID());
269cb6b059eSMatt Spinler }
270cb6b059eSMatt Spinler
flatten(std::vector<uint8_t> & pelBuffer) const2710688545bSMatt Spinler void PEL::flatten(std::vector<uint8_t>& pelBuffer) const
272cb6b059eSMatt Spinler {
273cb6b059eSMatt Spinler Stream pelData{pelBuffer};
274b832363dSMatt Spinler
27507eefc54SMatt Spinler if (!valid())
276cb6b059eSMatt Spinler {
277fd2da660SMatt Spinler lg2::warning("Unflattening an invalid PEL");
278cb6b059eSMatt Spinler }
279cb6b059eSMatt Spinler
28007eefc54SMatt Spinler _ph->flatten(pelData);
281cf5a8d0fSMatt Spinler _uh->flatten(pelData);
28207eefc54SMatt Spinler
28307eefc54SMatt Spinler for (auto& section : _optionalSections)
28407eefc54SMatt Spinler {
28507eefc54SMatt Spinler section->flatten(pelData);
28607eefc54SMatt Spinler }
287cb6b059eSMatt Spinler }
288cb6b059eSMatt Spinler
data() const2890688545bSMatt Spinler std::vector<uint8_t> PEL::data() const
290cb6b059eSMatt Spinler {
29107eefc54SMatt Spinler std::vector<uint8_t> pelData;
29207eefc54SMatt Spinler flatten(pelData);
29307eefc54SMatt Spinler return pelData;
294cb6b059eSMatt Spinler }
295cb6b059eSMatt Spinler
size() const296f1b46ff4SMatt Spinler size_t PEL::size() const
297f1b46ff4SMatt Spinler {
298f1b46ff4SMatt Spinler size_t size = 0;
299f1b46ff4SMatt Spinler
300f1b46ff4SMatt Spinler if (_ph)
301f1b46ff4SMatt Spinler {
302f1b46ff4SMatt Spinler size += _ph->header().size;
303f1b46ff4SMatt Spinler }
304f1b46ff4SMatt Spinler
305f1b46ff4SMatt Spinler if (_uh)
306f1b46ff4SMatt Spinler {
307f1b46ff4SMatt Spinler size += _uh->header().size;
308f1b46ff4SMatt Spinler }
309f1b46ff4SMatt Spinler
310f1b46ff4SMatt Spinler for (const auto& section : _optionalSections)
311f1b46ff4SMatt Spinler {
312f1b46ff4SMatt Spinler size += section->header().size;
313f1b46ff4SMatt Spinler }
314f1b46ff4SMatt Spinler
315f1b46ff4SMatt Spinler return size;
316f1b46ff4SMatt Spinler }
317f1b46ff4SMatt Spinler
primarySRC() const318bd716f00SMatt Spinler std::optional<SRC*> PEL::primarySRC() const
319bd716f00SMatt Spinler {
320075c7923SPatrick Williams auto src = std::find_if(
321075c7923SPatrick Williams _optionalSections.begin(), _optionalSections.end(), [](auto& section) {
322bd716f00SMatt Spinler return section->header().id ==
323bd716f00SMatt Spinler static_cast<uint16_t>(SectionID::primarySRC);
324bd716f00SMatt Spinler });
325bd716f00SMatt Spinler if (src != _optionalSections.end())
326bd716f00SMatt Spinler {
327bd716f00SMatt Spinler return static_cast<SRC*>(src->get());
328bd716f00SMatt Spinler }
329bd716f00SMatt Spinler
330bd716f00SMatt Spinler return std::nullopt;
331bd716f00SMatt Spinler }
332bd716f00SMatt Spinler
checkRulesAndFix()333f1e85e20SMatt Spinler void PEL::checkRulesAndFix()
334f1e85e20SMatt Spinler {
3351f93c590SMatt Spinler // Only fix if the action flags are at their default value which
3361f93c590SMatt Spinler // means they weren't specified in the registry. Otherwise
3371f93c590SMatt Spinler // assume the user knows what they are doing.
3381f93c590SMatt Spinler if (_uh->actionFlags() == actionFlagsDefault)
3391f93c590SMatt Spinler {
340075c7923SPatrick Williams auto [actionFlags, eventType] =
341075c7923SPatrick Williams pel_rules::check(0, _uh->eventType(), _uh->severity());
342f1e85e20SMatt Spinler
343f1e85e20SMatt Spinler _uh->setActionFlags(actionFlags);
344f1e85e20SMatt Spinler _uh->setEventType(eventType);
345f1e85e20SMatt Spinler }
3461f93c590SMatt Spinler }
347f1e85e20SMatt Spinler
printSectionInJSON(const Section & section,std::string & buf,std::map<uint16_t,size_t> & pluralSections,message::Registry & registry,const std::vector<std::string> & plugins,uint8_t creatorID) const348075c7923SPatrick Williams void PEL::printSectionInJSON(
349075c7923SPatrick Williams const Section& section, std::string& buf,
350075c7923SPatrick Williams std::map<uint16_t, size_t>& pluralSections, message::Registry& registry,
351075c7923SPatrick Williams const std::vector<std::string>& plugins, uint8_t creatorID) const
352186ce8c9SAatir {
353186ce8c9SAatir char tmpB[5];
354186ce8c9SAatir uint8_t id[] = {static_cast<uint8_t>(section.header().id >> 8),
355186ce8c9SAatir static_cast<uint8_t>(section.header().id)};
356186ce8c9SAatir sprintf(tmpB, "%c%c", id[0], id[1]);
357186ce8c9SAatir std::string sectionID(tmpB);
358186ce8c9SAatir std::string sectionName = pv::sectionTitles.count(sectionID)
359186ce8c9SAatir ? pv::sectionTitles.at(sectionID)
360186ce8c9SAatir : "Unknown Section";
361acb7c106SMatt Spinler
362acb7c106SMatt Spinler // Add a count if there are multiple of this type of section
363acb7c106SMatt Spinler auto count = pluralSections.find(section.header().id);
364acb7c106SMatt Spinler if (count != pluralSections.end())
365acb7c106SMatt Spinler {
366acb7c106SMatt Spinler sectionName += " " + std::to_string(count->second);
367acb7c106SMatt Spinler count->second++;
368acb7c106SMatt Spinler }
369acb7c106SMatt Spinler
370ad0e0476SAatir Manzur if (section.valid())
371ad0e0476SAatir Manzur {
372f67bafd0SHarisuddin Mohamed Isa std::optional<std::string> json;
373f67bafd0SHarisuddin Mohamed Isa if (sectionID == "PS" || sectionID == "SS")
374f67bafd0SHarisuddin Mohamed Isa {
375c8d6cc61SHarisuddin Mohamed Isa json = section.getJSON(registry, plugins, creatorID);
376f67bafd0SHarisuddin Mohamed Isa }
377386a61e6SMatt Spinler else if ((sectionID == "UD") || (sectionID == "ED"))
378f67bafd0SHarisuddin Mohamed Isa {
3793fdcd4e8SHarisuddin Mohamed Isa json = section.getJSON(creatorID, plugins);
380f67bafd0SHarisuddin Mohamed Isa }
381f67bafd0SHarisuddin Mohamed Isa else
382f67bafd0SHarisuddin Mohamed Isa {
383b832aa5eSMatt Spinler json = section.getJSON(creatorID);
384f67bafd0SHarisuddin Mohamed Isa }
3854220a158SMatt Spinler
3864220a158SMatt Spinler buf += "\"" + sectionName + "\": {\n";
3874220a158SMatt Spinler
388ad0e0476SAatir Manzur if (json)
389ad0e0476SAatir Manzur {
390600d15afSHarisuddin Mohamed Isa buf += *json + "\n},\n";
391ad0e0476SAatir Manzur }
392ad0e0476SAatir Manzur else
393ad0e0476SAatir Manzur {
3944220a158SMatt Spinler jsonInsert(buf, pv::sectionVer,
3954220a158SMatt Spinler getNumberString("%d", section.header().version), 1);
3964220a158SMatt Spinler jsonInsert(buf, pv::subSection,
3974220a158SMatt Spinler getNumberString("%d", section.header().subType), 1);
3984220a158SMatt Spinler jsonInsert(buf, pv::createdBy,
3994220a158SMatt Spinler getNumberString("0x%X", section.header().componentID),
4004220a158SMatt Spinler 1);
4014220a158SMatt Spinler
402186ce8c9SAatir std::vector<uint8_t> data;
403186ce8c9SAatir Stream s{data};
404186ce8c9SAatir section.flatten(s);
4054220a158SMatt Spinler std::string dstr =
4064220a158SMatt Spinler dumpHex(std::data(data) + SectionHeader::flattenedSize(),
4078c8aaa06SArya K Padman data.size() - SectionHeader::flattenedSize(), 2)
4088c8aaa06SArya K Padman .get();
4094220a158SMatt Spinler std::string jsonIndent(indentLevel, 0x20);
4104220a158SMatt Spinler buf += jsonIndent + "\"Data\": [\n";
4114220a158SMatt Spinler buf += dstr;
4124220a158SMatt Spinler buf += jsonIndent + "]\n";
4134220a158SMatt Spinler buf += "},\n";
414ad0e0476SAatir Manzur }
415186ce8c9SAatir }
416186ce8c9SAatir else
417186ce8c9SAatir {
418600d15afSHarisuddin Mohamed Isa buf += "\n\"Invalid Section\": [\n \"invalid\"\n],\n";
419186ce8c9SAatir }
420186ce8c9SAatir }
421186ce8c9SAatir
getPluralSections() const422acb7c106SMatt Spinler std::map<uint16_t, size_t> PEL::getPluralSections() const
423acb7c106SMatt Spinler {
424acb7c106SMatt Spinler std::map<uint16_t, size_t> sectionCounts;
425acb7c106SMatt Spinler
426acb7c106SMatt Spinler for (const auto& section : optionalSections())
427acb7c106SMatt Spinler {
428acb7c106SMatt Spinler if (sectionCounts.find(section->header().id) == sectionCounts.end())
429acb7c106SMatt Spinler {
430acb7c106SMatt Spinler sectionCounts[section->header().id] = 1;
431acb7c106SMatt Spinler }
432acb7c106SMatt Spinler else
433acb7c106SMatt Spinler {
434acb7c106SMatt Spinler sectionCounts[section->header().id]++;
435acb7c106SMatt Spinler }
436acb7c106SMatt Spinler }
437acb7c106SMatt Spinler
438acb7c106SMatt Spinler std::map<uint16_t, size_t> sections;
439acb7c106SMatt Spinler for (const auto& [id, count] : sectionCounts)
440acb7c106SMatt Spinler {
441acb7c106SMatt Spinler if (count > 1)
442acb7c106SMatt Spinler {
443acb7c106SMatt Spinler // Start with 0 here and printSectionInJSON()
444acb7c106SMatt Spinler // will increment it as it goes.
445acb7c106SMatt Spinler sections.emplace(id, 0);
446acb7c106SMatt Spinler }
447acb7c106SMatt Spinler }
448acb7c106SMatt Spinler
449acb7c106SMatt Spinler return sections;
450acb7c106SMatt Spinler }
451acb7c106SMatt Spinler
toJSON(message::Registry & registry,const std::vector<std::string> & plugins) const452f67bafd0SHarisuddin Mohamed Isa void PEL::toJSON(message::Registry& registry,
453f67bafd0SHarisuddin Mohamed Isa const std::vector<std::string>& plugins) const
454186ce8c9SAatir {
455acb7c106SMatt Spinler auto sections = getPluralSections();
456acb7c106SMatt Spinler
457a214ed30SHarisuddin Mohamed Isa std::string buf = "{\n";
458b832aa5eSMatt Spinler printSectionInJSON(*(_ph.get()), buf, sections, registry, plugins,
459b832aa5eSMatt Spinler _ph->creatorID());
460b832aa5eSMatt Spinler printSectionInJSON(*(_uh.get()), buf, sections, registry, plugins,
461b832aa5eSMatt Spinler _ph->creatorID());
462186ce8c9SAatir for (auto& section : this->optionalSections())
463186ce8c9SAatir {
464f67bafd0SHarisuddin Mohamed Isa printSectionInJSON(*(section.get()), buf, sections, registry, plugins,
465f67bafd0SHarisuddin Mohamed Isa _ph->creatorID());
466186ce8c9SAatir }
467186ce8c9SAatir buf += "}";
468186ce8c9SAatir std::size_t found = buf.rfind(",");
469186ce8c9SAatir if (found != std::string::npos)
470186ce8c9SAatir buf.replace(found, 1, "");
471186ce8c9SAatir std::cout << buf << std::endl;
472186ce8c9SAatir }
473600d15afSHarisuddin Mohamed Isa
addUserDataSection(std::unique_ptr<UserData> userData)47485f61a63SMatt Spinler bool PEL::addUserDataSection(std::unique_ptr<UserData> userData)
47585f61a63SMatt Spinler {
47685f61a63SMatt Spinler if (size() + userData->header().size > _maxPELSize)
47785f61a63SMatt Spinler {
47885f61a63SMatt Spinler if (userData->shrink(_maxPELSize - size()))
47985f61a63SMatt Spinler {
48085f61a63SMatt Spinler _optionalSections.push_back(std::move(userData));
48185f61a63SMatt Spinler }
48285f61a63SMatt Spinler else
48385f61a63SMatt Spinler {
484fd2da660SMatt Spinler lg2::warning("Could not shrink UserData section. Dropping. "
485fd2da660SMatt Spinler "Section size = {SSIZE}, Component ID = {COMP_ID}, "
486fd2da660SMatt Spinler "Subtype = {SUBTYPE}, Version = {VERSION}",
487fd2da660SMatt Spinler "SSIZE", userData->header().size, "COMP_ID",
488fd2da660SMatt Spinler userData->header().componentID, "SUBTYPE",
489fd2da660SMatt Spinler userData->header().subType, "VERSION",
490fd2da660SMatt Spinler userData->header().version);
49185f61a63SMatt Spinler return false;
49285f61a63SMatt Spinler }
49385f61a63SMatt Spinler }
49485f61a63SMatt Spinler else
49585f61a63SMatt Spinler {
49685f61a63SMatt Spinler _optionalSections.push_back(std::move(userData));
49785f61a63SMatt Spinler }
49885f61a63SMatt Spinler return true;
49985f61a63SMatt Spinler }
50085f61a63SMatt Spinler
getCalloutJSON(const PelFFDC & ffdcFiles)5015a90a95bSMatt Spinler nlohmann::json PEL::getCalloutJSON(const PelFFDC& ffdcFiles)
5025a90a95bSMatt Spinler {
5035a90a95bSMatt Spinler nlohmann::json callouts;
5045a90a95bSMatt Spinler
5055a90a95bSMatt Spinler for (const auto& file : ffdcFiles)
5065a90a95bSMatt Spinler {
5075a90a95bSMatt Spinler if ((file.format == UserDataFormat::json) &&
5085a90a95bSMatt Spinler (file.subType == jsonCalloutSubtype))
5095a90a95bSMatt Spinler {
5105a90a95bSMatt Spinler auto data = util::readFD(file.fd);
5115a90a95bSMatt Spinler if (data.empty())
5125a90a95bSMatt Spinler {
5135a90a95bSMatt Spinler throw std::runtime_error{
5145a90a95bSMatt Spinler "Could not get data from JSON callout file descriptor"};
5155a90a95bSMatt Spinler }
5165a90a95bSMatt Spinler
5175a90a95bSMatt Spinler std::string jsonString{data.begin(), data.begin() + data.size()};
5185a90a95bSMatt Spinler
5195a90a95bSMatt Spinler callouts = nlohmann::json::parse(jsonString);
5205a90a95bSMatt Spinler break;
5215a90a95bSMatt Spinler }
5225a90a95bSMatt Spinler }
5235a90a95bSMatt Spinler
5245a90a95bSMatt Spinler return callouts;
5255a90a95bSMatt Spinler }
5265a90a95bSMatt Spinler
isHwCalloutPresent() const527f8e750ddSAndrew Geissler bool PEL::isHwCalloutPresent() const
52844fc3168SAndrew Geissler {
52944fc3168SAndrew Geissler auto pSRC = primarySRC();
53044fc3168SAndrew Geissler if (!pSRC)
53144fc3168SAndrew Geissler {
53244fc3168SAndrew Geissler return false;
53344fc3168SAndrew Geissler }
53444fc3168SAndrew Geissler
53544fc3168SAndrew Geissler bool calloutPresent = false;
53644fc3168SAndrew Geissler if ((*pSRC)->callouts())
53744fc3168SAndrew Geissler {
53844fc3168SAndrew Geissler for (auto& i : (*pSRC)->callouts()->callouts())
53944fc3168SAndrew Geissler {
54044fc3168SAndrew Geissler if (((*i).fruIdentity()))
54144fc3168SAndrew Geissler {
54244fc3168SAndrew Geissler auto& fruId = (*i).fruIdentity();
543f8e750ddSAndrew Geissler if ((*fruId).failingComponentType() ==
544f8e750ddSAndrew Geissler src::FRUIdentity::hardwareFRU)
54544fc3168SAndrew Geissler {
54644fc3168SAndrew Geissler calloutPresent = true;
54744fc3168SAndrew Geissler break;
54844fc3168SAndrew Geissler }
54944fc3168SAndrew Geissler }
55044fc3168SAndrew Geissler }
55144fc3168SAndrew Geissler }
55244fc3168SAndrew Geissler
55344fc3168SAndrew Geissler return calloutPresent;
55444fc3168SAndrew Geissler }
55544fc3168SAndrew Geissler
updateSysInfoInExtendedUserDataSection(const DataInterfaceBase & dataIface)5563160a544SSumit Kumar void PEL::updateSysInfoInExtendedUserDataSection(
5573160a544SSumit Kumar const DataInterfaceBase& dataIface)
5583160a544SSumit Kumar {
5593160a544SSumit Kumar const AdditionalData additionalData;
5603160a544SSumit Kumar
5613160a544SSumit Kumar // Check for PEL from Hostboot
5623160a544SSumit Kumar if (_ph->creatorID() == static_cast<uint8_t>(CreatorID::hostboot))
5633160a544SSumit Kumar {
5643160a544SSumit Kumar // Get the ED section from PEL
565075c7923SPatrick Williams auto op = std::find_if(
566075c7923SPatrick Williams _optionalSections.begin(), _optionalSections.end(),
567075c7923SPatrick Williams [](auto& section) {
5683160a544SSumit Kumar return section->header().id ==
569ac1ba3f2SPatrick Williams static_cast<uint16_t>(SectionID::extUserData);
5703160a544SSumit Kumar });
5713160a544SSumit Kumar
5723160a544SSumit Kumar // Check for ED section found and its not the last section of PEL
5733160a544SSumit Kumar if (op != _optionalSections.end())
5743160a544SSumit Kumar {
5753160a544SSumit Kumar // Get the extended user data class mapped to found section
5763160a544SSumit Kumar auto extUserData = static_cast<ExtendedUserData*>(op->get());
5773160a544SSumit Kumar
5783160a544SSumit Kumar // Check for the creator ID is for OpenBMC
5793160a544SSumit Kumar if (extUserData->creatorID() ==
5803160a544SSumit Kumar static_cast<uint8_t>(CreatorID::openBMC))
5813160a544SSumit Kumar {
5823160a544SSumit Kumar // Update subtype and component id
5833160a544SSumit Kumar auto subType = static_cast<uint8_t>(UserDataFormat::json);
5843160a544SSumit Kumar auto componentId =
5853160a544SSumit Kumar static_cast<uint16_t>(ComponentID::phosphorLogging);
5863160a544SSumit Kumar
5873160a544SSumit Kumar // Update system data to ED section
5889ac0d9b8SGeorge Liu auto ud = util::makeSysInfoUserDataSection(additionalData,
5899ac0d9b8SGeorge Liu dataIface, false);
5903160a544SSumit Kumar extUserData->updateDataSection(subType, componentId,
5913160a544SSumit Kumar ud->data());
5923160a544SSumit Kumar }
5933160a544SSumit Kumar }
5943160a544SSumit Kumar }
5953160a544SSumit Kumar }
5963160a544SSumit Kumar
getDeconfigFlag() const5978e65f4eaSMatt Spinler bool PEL::getDeconfigFlag() const
5988e65f4eaSMatt Spinler {
5998e65f4eaSMatt Spinler auto creator = static_cast<CreatorID>(_ph->creatorID());
6008e65f4eaSMatt Spinler
6018e65f4eaSMatt Spinler if ((creator == CreatorID::openBMC) || (creator == CreatorID::hostboot))
6028e65f4eaSMatt Spinler {
6038e65f4eaSMatt Spinler auto src = primarySRC();
6048e65f4eaSMatt Spinler return (*src)->getErrorStatusFlag(SRC::ErrorStatusFlags::deconfigured);
6058e65f4eaSMatt Spinler }
6068e65f4eaSMatt Spinler return false;
6078e65f4eaSMatt Spinler }
6088e65f4eaSMatt Spinler
getGuardFlag() const6098e65f4eaSMatt Spinler bool PEL::getGuardFlag() const
6108e65f4eaSMatt Spinler {
6118e65f4eaSMatt Spinler auto creator = static_cast<CreatorID>(_ph->creatorID());
6128e65f4eaSMatt Spinler
6138e65f4eaSMatt Spinler if ((creator == CreatorID::openBMC) || (creator == CreatorID::hostboot))
6148e65f4eaSMatt Spinler {
6158e65f4eaSMatt Spinler auto src = primarySRC();
6168e65f4eaSMatt Spinler return (*src)->getErrorStatusFlag(SRC::ErrorStatusFlags::guarded);
6178e65f4eaSMatt Spinler }
6188e65f4eaSMatt Spinler return false;
6198e65f4eaSMatt Spinler }
6208e65f4eaSMatt Spinler
updateTerminateBitInSRCSection()6213e274432SSumit Kumar void PEL::updateTerminateBitInSRCSection()
6223e274432SSumit Kumar {
6233e274432SSumit Kumar // Check for pel severity of type - 0x51 = critical error, system
6243e274432SSumit Kumar // termination
6253e274432SSumit Kumar if (_uh->severity() == 0x51)
6263e274432SSumit Kumar {
6273e274432SSumit Kumar // Get the primary SRC section
6283e274432SSumit Kumar auto pSRC = primarySRC();
6293e274432SSumit Kumar if (pSRC)
6303e274432SSumit Kumar {
6313e274432SSumit Kumar (*pSRC)->setTerminateBit();
6323e274432SSumit Kumar }
6333e274432SSumit Kumar }
6343e274432SSumit Kumar }
6353e274432SSumit Kumar
addJournalSections(const message::Entry & regEntry,const JournalBase & journal)6369d921096SMatt Spinler void PEL::addJournalSections(const message::Entry& regEntry,
6379d921096SMatt Spinler const JournalBase& journal)
6389d921096SMatt Spinler {
6399d921096SMatt Spinler if (!regEntry.journalCapture)
6409d921096SMatt Spinler {
6419d921096SMatt Spinler return;
6429d921096SMatt Spinler }
6439d921096SMatt Spinler
6449d921096SMatt Spinler // Write all unwritten journal data to disk.
6459d921096SMatt Spinler journal.sync();
6469d921096SMatt Spinler
6479d921096SMatt Spinler const auto& jc = regEntry.journalCapture.value();
6489d921096SMatt Spinler std::vector<std::vector<std::string>> allMessages;
6499d921096SMatt Spinler
6509d921096SMatt Spinler if (std::holds_alternative<size_t>(jc))
6519d921096SMatt Spinler {
6529d921096SMatt Spinler // Get the previous numLines journal entries
6539d921096SMatt Spinler const auto& numLines = std::get<size_t>(jc);
6549d921096SMatt Spinler try
6559d921096SMatt Spinler {
6569d921096SMatt Spinler auto messages = journal.getMessages("", numLines);
6579d921096SMatt Spinler if (!messages.empty())
6589d921096SMatt Spinler {
6599d921096SMatt Spinler allMessages.push_back(std::move(messages));
6609d921096SMatt Spinler }
6619d921096SMatt Spinler }
6629d921096SMatt Spinler catch (const std::exception& e)
6639d921096SMatt Spinler {
664fd2da660SMatt Spinler lg2::error("Failed during journal collection: {ERROR}", "ERROR", e);
6659d921096SMatt Spinler }
6669d921096SMatt Spinler }
6679d921096SMatt Spinler else if (std::holds_alternative<message::AppCaptureList>(jc))
6689d921096SMatt Spinler {
6699d921096SMatt Spinler // Get journal entries based on the syslog id field.
6709d921096SMatt Spinler const auto& sections = std::get<message::AppCaptureList>(jc);
6719d921096SMatt Spinler for (const auto& [syslogID, numLines] : sections)
6729d921096SMatt Spinler {
6739d921096SMatt Spinler try
6749d921096SMatt Spinler {
6759d921096SMatt Spinler auto messages = journal.getMessages(syslogID, numLines);
6769d921096SMatt Spinler if (!messages.empty())
6779d921096SMatt Spinler {
6789d921096SMatt Spinler allMessages.push_back(std::move(messages));
6799d921096SMatt Spinler }
6809d921096SMatt Spinler }
6819d921096SMatt Spinler catch (const std::exception& e)
6829d921096SMatt Spinler {
683fd2da660SMatt Spinler lg2::error("Failed during journal collection: {ERROR}", "ERROR",
684fd2da660SMatt Spinler e);
6859d921096SMatt Spinler }
6869d921096SMatt Spinler }
6879d921096SMatt Spinler }
6889d921096SMatt Spinler
6899d921096SMatt Spinler // Create the UserData sections
6909d921096SMatt Spinler for (const auto& messages : allMessages)
6919d921096SMatt Spinler {
6929d921096SMatt Spinler auto buffer = util::flattenLines(messages);
6939d921096SMatt Spinler
6949d921096SMatt Spinler // If the buffer is way too big, it can overflow the uint16_t
6959d921096SMatt Spinler // PEL section size field that is checked below so do a cursory
6969d921096SMatt Spinler // check here.
6979d921096SMatt Spinler if (buffer.size() > _maxPELSize)
6989d921096SMatt Spinler {
699fd2da660SMatt Spinler lg2::warning(
700fd2da660SMatt Spinler "Journal UserData section does not fit in PEL, dropping. "
701fd2da660SMatt Spinler "PEL size = {PEL_SIZE}, data size = {DATA_SIZE}",
702fd2da660SMatt Spinler "PEL_SIZE", size(), "DATA_SIZE", buffer.size());
7039d921096SMatt Spinler continue;
7049d921096SMatt Spinler }
7059d921096SMatt Spinler
7069d921096SMatt Spinler // Sections must be 4 byte aligned.
7079d921096SMatt Spinler while (buffer.size() % 4 != 0)
7089d921096SMatt Spinler {
7099d921096SMatt Spinler buffer.push_back(0);
7109d921096SMatt Spinler }
7119d921096SMatt Spinler
7129d921096SMatt Spinler auto ud = std::make_unique<UserData>(
7139d921096SMatt Spinler static_cast<uint16_t>(ComponentID::phosphorLogging),
7149d921096SMatt Spinler static_cast<uint8_t>(UserDataFormat::text),
7159d921096SMatt Spinler static_cast<uint8_t>(UserDataFormatVersion::text), buffer);
7169d921096SMatt Spinler
7179d921096SMatt Spinler if (size() + ud->header().size <= _maxPELSize)
7189d921096SMatt Spinler {
7199d921096SMatt Spinler _optionalSections.push_back(std::move(ud));
7209d921096SMatt Spinler }
7219d921096SMatt Spinler else
7229d921096SMatt Spinler {
7239d921096SMatt Spinler // Don't attempt to shrink here since we'd be dropping the
7249d921096SMatt Spinler // most recent journal entries which would be confusing.
725fd2da660SMatt Spinler lg2::warning(
726fd2da660SMatt Spinler "Journal UserData section does not fit in PEL, dropping. "
727fd2da660SMatt Spinler "PEL size = {PEL_SIZE}, data size = {DATA_SIZE}",
728fd2da660SMatt Spinler "PEL_SIZE", size(), "DATA_SIZE", buffer.size());
7299d921096SMatt Spinler ud.reset();
7309d921096SMatt Spinler continue;
7319d921096SMatt Spinler }
7329d921096SMatt Spinler }
7339d921096SMatt Spinler }
7349d921096SMatt Spinler
addAdDetailsForDIMMsCallout(const std::unique_ptr<SRC> & src,const DataInterfaceBase & dataIface,nlohmann::json & adSysInfoData,DebugData & debugData)735d8ae618aSArya K Padman void PEL::addAdDetailsForDIMMsCallout(
736d8ae618aSArya K Padman const std::unique_ptr<SRC>& src, const DataInterfaceBase& dataIface,
737d8ae618aSArya K Padman nlohmann::json& adSysInfoData, DebugData& debugData)
738d8ae618aSArya K Padman {
739d8ae618aSArya K Padman if (!src->callouts())
740d8ae618aSArya K Padman {
741d8ae618aSArya K Padman // No callouts
742d8ae618aSArya K Padman return;
743d8ae618aSArya K Padman }
744d8ae618aSArya K Padman
745d8ae618aSArya K Padman auto isDIMMCallout = [&dataIface, &debugData](const auto& callout) {
746d8ae618aSArya K Padman auto locCode{callout->locationCode()};
747d8ae618aSArya K Padman if (locCode.empty())
748d8ae618aSArya K Padman {
749d8ae618aSArya K Padman // Not a hardware callout. No action required
750d8ae618aSArya K Padman return false;
751d8ae618aSArya K Padman }
752d8ae618aSArya K Padman else
753d8ae618aSArya K Padman {
754ced8ed77SArya K Padman return const_cast<DataInterfaceBase&>(dataIface).isDIMM(locCode);
755d8ae618aSArya K Padman }
756d8ae618aSArya K Padman };
757d8ae618aSArya K Padman auto addAdDIMMDetails = [&dataIface, &adSysInfoData,
758d8ae618aSArya K Padman &debugData](const auto& callout) {
759d8ae618aSArya K Padman auto dimmLocCode{callout->locationCode()};
760d8ae618aSArya K Padman
761d8ae618aSArya K Padman auto diPropVal = dataIface.getDIProperty(dimmLocCode);
762d8ae618aSArya K Padman if (!diPropVal.has_value())
763d8ae618aSArya K Padman {
764d8ae618aSArya K Padman std::string errMsg{
765d8ae618aSArya K Padman std::format("Failed reading DI property from "
766d8ae618aSArya K Padman "VINI Interface for the LocationCode:[{}]",
767d8ae618aSArya K Padman dimmLocCode)};
768d8ae618aSArya K Padman debugData[AdDIMMInfoFetchError].emplace_back(errMsg);
769d8ae618aSArya K Padman }
770d8ae618aSArya K Padman else
771d8ae618aSArya K Padman {
772d8ae618aSArya K Padman util::addDIMMInfo(dimmLocCode, diPropVal.value(), adSysInfoData);
773d8ae618aSArya K Padman }
774d8ae618aSArya K Padman };
775d8ae618aSArya K Padman
776d8ae618aSArya K Padman auto DIMMsCallouts = src->callouts()->callouts() |
777d8ae618aSArya K Padman std::views::filter(isDIMMCallout);
778d8ae618aSArya K Padman
779d8ae618aSArya K Padman std::ranges::for_each(DIMMsCallouts, addAdDIMMDetails);
780d8ae618aSArya K Padman }
781d8ae618aSArya K Padman
782c7c3e402SMatt Spinler namespace util
783c7c3e402SMatt Spinler {
784c7c3e402SMatt Spinler
makeJSONUserDataSection(const nlohmann::json & json)7854dcd3f46SMatt Spinler std::unique_ptr<UserData> makeJSONUserDataSection(const nlohmann::json& json)
7864dcd3f46SMatt Spinler {
78713db1d38SMatt Spinler std::string jsonString;
78813db1d38SMatt Spinler try
78913db1d38SMatt Spinler {
79013db1d38SMatt Spinler jsonString = json.dump();
79113db1d38SMatt Spinler }
79213db1d38SMatt Spinler catch (const std::exception& e)
79313db1d38SMatt Spinler {
79413db1d38SMatt Spinler lg2::error("json.dump() failed with: {ERROR}", "ERROR", e);
79513db1d38SMatt Spinler jsonString = "Invalid JSON passed to makeJSONUserDataSection!";
79613db1d38SMatt Spinler }
79713db1d38SMatt Spinler
7984dcd3f46SMatt Spinler std::vector<uint8_t> jsonData(jsonString.begin(), jsonString.end());
7994dcd3f46SMatt Spinler
8004dcd3f46SMatt Spinler // Pad to a 4 byte boundary
8014dcd3f46SMatt Spinler while ((jsonData.size() % 4) != 0)
8024dcd3f46SMatt Spinler {
8034dcd3f46SMatt Spinler jsonData.push_back(0);
8044dcd3f46SMatt Spinler }
8054dcd3f46SMatt Spinler
8064dcd3f46SMatt Spinler return std::make_unique<UserData>(
8074dcd3f46SMatt Spinler static_cast<uint16_t>(ComponentID::phosphorLogging),
8084dcd3f46SMatt Spinler static_cast<uint8_t>(UserDataFormat::json),
8094dcd3f46SMatt Spinler static_cast<uint8_t>(UserDataFormatVersion::json), jsonData);
8104dcd3f46SMatt Spinler }
8114dcd3f46SMatt Spinler
makeADUserDataSection(const AdditionalData & ad)812c7c3e402SMatt Spinler std::unique_ptr<UserData> makeADUserDataSection(const AdditionalData& ad)
813c7c3e402SMatt Spinler {
814c7c3e402SMatt Spinler assert(!ad.empty());
815c7c3e402SMatt Spinler nlohmann::json json;
816c7c3e402SMatt Spinler
817c7c3e402SMatt Spinler // Remove the 'ESEL' entry, as it contains a full PEL in the value.
818c7c3e402SMatt Spinler if (ad.getValue("ESEL"))
819c7c3e402SMatt Spinler {
820c7c3e402SMatt Spinler auto newAD = ad;
821c7c3e402SMatt Spinler newAD.remove("ESEL");
822c7c3e402SMatt Spinler json = newAD.toJSON();
823c7c3e402SMatt Spinler }
824c7c3e402SMatt Spinler else
825c7c3e402SMatt Spinler {
826c7c3e402SMatt Spinler json = ad.toJSON();
827c7c3e402SMatt Spinler }
828c7c3e402SMatt Spinler
8294dcd3f46SMatt Spinler return makeJSONUserDataSection(json);
830c7c3e402SMatt Spinler }
831c7c3e402SMatt Spinler
addProcessNameToJSON(nlohmann::json & json,const std::optional<std::string> & pid,const DataInterfaceBase & dataIface)8324dcd3f46SMatt Spinler void addProcessNameToJSON(nlohmann::json& json,
8334dcd3f46SMatt Spinler const std::optional<std::string>& pid,
8344dcd3f46SMatt Spinler const DataInterfaceBase& dataIface)
8354dcd3f46SMatt Spinler {
836677381b8SMatt Spinler std::string name{unknownValue};
8374dcd3f46SMatt Spinler
8384dcd3f46SMatt Spinler try
8394dcd3f46SMatt Spinler {
8404dcd3f46SMatt Spinler if (pid)
8414dcd3f46SMatt Spinler {
8424dcd3f46SMatt Spinler auto n = dataIface.getProcessName(*pid);
8434dcd3f46SMatt Spinler if (n)
8444dcd3f46SMatt Spinler {
8454dcd3f46SMatt Spinler name = *n;
8464dcd3f46SMatt Spinler }
8474dcd3f46SMatt Spinler }
8484dcd3f46SMatt Spinler }
84966491c61SPatrick Williams catch (const std::exception& e)
8502544b419SPatrick Williams {}
8514dcd3f46SMatt Spinler
8523160a544SSumit Kumar if (pid)
8533160a544SSumit Kumar {
8544dcd3f46SMatt Spinler json["Process Name"] = std::move(name);
8554dcd3f46SMatt Spinler }
8563160a544SSumit Kumar }
8574dcd3f46SMatt Spinler
addBMCFWVersionIDToJSON(nlohmann::json & json,const DataInterfaceBase & dataIface)858677381b8SMatt Spinler void addBMCFWVersionIDToJSON(nlohmann::json& json,
859677381b8SMatt Spinler const DataInterfaceBase& dataIface)
860677381b8SMatt Spinler {
861677381b8SMatt Spinler auto id = dataIface.getBMCFWVersionID();
862677381b8SMatt Spinler if (id.empty())
863677381b8SMatt Spinler {
864677381b8SMatt Spinler id = unknownValue;
865677381b8SMatt Spinler }
866677381b8SMatt Spinler
867c2b8a517SMatt Spinler json["FW Version ID"] = std::move(id);
868677381b8SMatt Spinler }
869677381b8SMatt Spinler
lastSegment(char separator,std::string data)8704aa23a1fSMatt Spinler std::string lastSegment(char separator, std::string data)
8714aa23a1fSMatt Spinler {
8724aa23a1fSMatt Spinler auto pos = data.find_last_of(separator);
8734aa23a1fSMatt Spinler if (pos != std::string::npos)
8744aa23a1fSMatt Spinler {
8754aa23a1fSMatt Spinler data = data.substr(pos + 1);
8764aa23a1fSMatt Spinler }
8774aa23a1fSMatt Spinler
8784aa23a1fSMatt Spinler return data;
8794aa23a1fSMatt Spinler }
8804aa23a1fSMatt Spinler
addIMKeyword(nlohmann::json & json,const DataInterfaceBase & dataIface)881e32b7e76SBen Tyner void addIMKeyword(nlohmann::json& json, const DataInterfaceBase& dataIface)
882e32b7e76SBen Tyner {
883e32b7e76SBen Tyner auto keyword = dataIface.getSystemIMKeyword();
884e32b7e76SBen Tyner
885e32b7e76SBen Tyner std::string value{};
886e32b7e76SBen Tyner
887e32b7e76SBen Tyner std::for_each(keyword.begin(), keyword.end(), [&](const auto& byte) {
8881aa90d49SJayanth Othayoth value += std::format("{:02X}", byte);
889e32b7e76SBen Tyner });
890e32b7e76SBen Tyner
891e32b7e76SBen Tyner json["System IM"] = value;
892e32b7e76SBen Tyner }
893e32b7e76SBen Tyner
addStatesToJSON(nlohmann::json & json,const DataInterfaceBase & dataIface)8944aa23a1fSMatt Spinler void addStatesToJSON(nlohmann::json& json, const DataInterfaceBase& dataIface)
8954aa23a1fSMatt Spinler {
8964aa23a1fSMatt Spinler json["BMCState"] = lastSegment('.', dataIface.getBMCState());
8974aa23a1fSMatt Spinler json["ChassisState"] = lastSegment('.', dataIface.getChassisState());
8984aa23a1fSMatt Spinler json["HostState"] = lastSegment('.', dataIface.getHostState());
8992c36fddcSSumit Kumar json["BootState"] = lastSegment('.', dataIface.getBootState());
9004aa23a1fSMatt Spinler }
9014aa23a1fSMatt Spinler
addBMCUptime(nlohmann::json & json,const DataInterfaceBase & dataIface)9029ac0d9b8SGeorge Liu void addBMCUptime(nlohmann::json& json, const DataInterfaceBase& dataIface)
9039ac0d9b8SGeorge Liu {
9049ac0d9b8SGeorge Liu auto seconds = dataIface.getUptimeInSeconds();
9059ac0d9b8SGeorge Liu if (seconds)
9069ac0d9b8SGeorge Liu {
9079ac0d9b8SGeorge Liu json["BMCUptime"] = dataIface.getBMCUptime(*seconds);
9089ac0d9b8SGeorge Liu }
9099ac0d9b8SGeorge Liu else
9109ac0d9b8SGeorge Liu {
9119ac0d9b8SGeorge Liu json["BMCUptime"] = "";
9129ac0d9b8SGeorge Liu }
9139ac0d9b8SGeorge Liu json["BMCLoad"] = dataIface.getBMCLoadAvg();
9149ac0d9b8SGeorge Liu }
9159ac0d9b8SGeorge Liu
makeSysInfoUserDataSection(const AdditionalData & ad,const DataInterfaceBase & dataIface,bool addUptime,const nlohmann::json & adSysInfoData)916075c7923SPatrick Williams std::unique_ptr<UserData> makeSysInfoUserDataSection(
917075c7923SPatrick Williams const AdditionalData& ad, const DataInterfaceBase& dataIface,
918d8ae618aSArya K Padman bool addUptime, const nlohmann::json& adSysInfoData)
9194dcd3f46SMatt Spinler {
9204dcd3f46SMatt Spinler nlohmann::json json;
9214dcd3f46SMatt Spinler
9224dcd3f46SMatt Spinler addProcessNameToJSON(json, ad.getValue("_PID"), dataIface);
923677381b8SMatt Spinler addBMCFWVersionIDToJSON(json, dataIface);
924e32b7e76SBen Tyner addIMKeyword(json, dataIface);
9254aa23a1fSMatt Spinler addStatesToJSON(json, dataIface);
9264dcd3f46SMatt Spinler
9279ac0d9b8SGeorge Liu if (addUptime)
9289ac0d9b8SGeorge Liu {
9299ac0d9b8SGeorge Liu addBMCUptime(json, dataIface);
9309ac0d9b8SGeorge Liu }
9319ac0d9b8SGeorge Liu
932d8ae618aSArya K Padman if (!adSysInfoData.empty())
933d8ae618aSArya K Padman {
934d8ae618aSArya K Padman json.update(adSysInfoData);
935d8ae618aSArya K Padman }
936d8ae618aSArya K Padman
9374dcd3f46SMatt Spinler return makeJSONUserDataSection(json);
938c7c3e402SMatt Spinler }
939c7c3e402SMatt Spinler
readFD(int fd)9405b289b23SMatt Spinler std::vector<uint8_t> readFD(int fd)
9415b289b23SMatt Spinler {
9425b289b23SMatt Spinler std::vector<uint8_t> data;
9435b289b23SMatt Spinler
9445b289b23SMatt Spinler // Get the size
9455b289b23SMatt Spinler struct stat s;
9465b289b23SMatt Spinler int r = fstat(fd, &s);
9475b289b23SMatt Spinler if (r != 0)
9485b289b23SMatt Spinler {
9495b289b23SMatt Spinler auto e = errno;
950fd2da660SMatt Spinler lg2::error("Could not get FFDC file size from FD, errno = {ERRNO}",
951fd2da660SMatt Spinler "ERRNO", e);
9525b289b23SMatt Spinler return data;
9535b289b23SMatt Spinler }
9545b289b23SMatt Spinler
9555b289b23SMatt Spinler if (0 == s.st_size)
9565b289b23SMatt Spinler {
957fd2da660SMatt Spinler lg2::error("FFDC file is empty");
9585b289b23SMatt Spinler return data;
9595b289b23SMatt Spinler }
9605b289b23SMatt Spinler
9615b289b23SMatt Spinler data.resize(s.st_size);
9625b289b23SMatt Spinler
9635b289b23SMatt Spinler // Make sure its at the beginning, as maybe another
9645b289b23SMatt Spinler // extension already used it.
9655b289b23SMatt Spinler r = lseek(fd, 0, SEEK_SET);
9665b289b23SMatt Spinler if (r == -1)
9675b289b23SMatt Spinler {
9685b289b23SMatt Spinler auto e = errno;
969fd2da660SMatt Spinler lg2::error("Could not seek to beginning of FFDC file, errno = {ERRNO}",
970fd2da660SMatt Spinler "ERRNO", e);
9715b289b23SMatt Spinler return data;
9725b289b23SMatt Spinler }
9735b289b23SMatt Spinler
9745b289b23SMatt Spinler r = read(fd, data.data(), s.st_size);
9755b289b23SMatt Spinler if (r == -1)
9765b289b23SMatt Spinler {
9775b289b23SMatt Spinler auto e = errno;
978fd2da660SMatt Spinler lg2::error("Could not read FFDC file, errno = {ERRNO}", "ERRNO", e);
9795b289b23SMatt Spinler }
9805b289b23SMatt Spinler else if (r != s.st_size)
9815b289b23SMatt Spinler {
982fd2da660SMatt Spinler lg2::warning("Could not read full FFDC file. "
983fd2da660SMatt Spinler "File size = {FSIZE}, Size read = {SIZE_READ}",
984fd2da660SMatt Spinler "FSIZE", s.st_size, "SIZE_READ", r);
9855b289b23SMatt Spinler }
9865b289b23SMatt Spinler
9875b289b23SMatt Spinler return data;
9885b289b23SMatt Spinler }
9895b289b23SMatt Spinler
makeFFDCuserDataSection(uint16_t componentID,const PelFFDCfile & file)990*25291157SPatrick Williams std::unique_ptr<UserData> makeFFDCuserDataSection(uint16_t componentID,
991*25291157SPatrick Williams const PelFFDCfile& file)
99256ad2a0eSMatt Spinler {
9935b289b23SMatt Spinler auto data = readFD(file.fd);
9945b289b23SMatt Spinler
9955b289b23SMatt Spinler if (data.empty())
9965b289b23SMatt Spinler {
99756ad2a0eSMatt Spinler return std::unique_ptr<UserData>();
99856ad2a0eSMatt Spinler }
99956ad2a0eSMatt Spinler
10005b289b23SMatt Spinler // The data needs 4 Byte alignment, and save amount padded for the
10015b289b23SMatt Spinler // CBOR case.
10025b289b23SMatt Spinler uint32_t pad = 0;
10035b289b23SMatt Spinler while (data.size() % 4)
10045b289b23SMatt Spinler {
10055b289b23SMatt Spinler data.push_back(0);
10065b289b23SMatt Spinler pad++;
10075b289b23SMatt Spinler }
10085b289b23SMatt Spinler
10095b289b23SMatt Spinler // For JSON, CBOR, and Text use our component ID, subType, and version,
10105b289b23SMatt Spinler // otherwise use the supplied ones.
10115b289b23SMatt Spinler uint16_t compID = static_cast<uint16_t>(ComponentID::phosphorLogging);
10125b289b23SMatt Spinler uint8_t subType{};
10135b289b23SMatt Spinler uint8_t version{};
10145b289b23SMatt Spinler
10155b289b23SMatt Spinler switch (file.format)
10165b289b23SMatt Spinler {
10175b289b23SMatt Spinler case UserDataFormat::json:
10185b289b23SMatt Spinler subType = static_cast<uint8_t>(UserDataFormat::json);
10195b289b23SMatt Spinler version = static_cast<uint8_t>(UserDataFormatVersion::json);
10205b289b23SMatt Spinler break;
10215b289b23SMatt Spinler case UserDataFormat::cbor:
10225b289b23SMatt Spinler subType = static_cast<uint8_t>(UserDataFormat::cbor);
10235b289b23SMatt Spinler version = static_cast<uint8_t>(UserDataFormatVersion::cbor);
10245b289b23SMatt Spinler
10255b289b23SMatt Spinler // The CBOR parser will fail on the extra pad bytes since they
10265b289b23SMatt Spinler // aren't CBOR. Add the amount we padded to the end and other
10275b289b23SMatt Spinler // code will remove it all before parsing.
10285b289b23SMatt Spinler {
10295b289b23SMatt Spinler data.resize(data.size() + 4);
10305b289b23SMatt Spinler Stream stream{data};
10315b289b23SMatt Spinler stream.offset(data.size() - 4);
10325b289b23SMatt Spinler stream << pad;
10335b289b23SMatt Spinler }
10345b289b23SMatt Spinler
10355b289b23SMatt Spinler break;
10365b289b23SMatt Spinler case UserDataFormat::text:
10375b289b23SMatt Spinler subType = static_cast<uint8_t>(UserDataFormat::text);
10385b289b23SMatt Spinler version = static_cast<uint8_t>(UserDataFormatVersion::text);
10395b289b23SMatt Spinler break;
10405b289b23SMatt Spinler case UserDataFormat::custom:
10415b289b23SMatt Spinler default:
10425b289b23SMatt Spinler // Use the passed in values
10435b289b23SMatt Spinler compID = componentID;
10445b289b23SMatt Spinler subType = file.subType;
10455b289b23SMatt Spinler version = file.version;
10465b289b23SMatt Spinler break;
10475b289b23SMatt Spinler }
10485b289b23SMatt Spinler
10495b289b23SMatt Spinler return std::make_unique<UserData>(compID, subType, version, data);
10505b289b23SMatt Spinler }
10515b289b23SMatt Spinler
flattenLines(const std::vector<std::string> & lines)10529d921096SMatt Spinler std::vector<uint8_t> flattenLines(const std::vector<std::string>& lines)
10539d921096SMatt Spinler {
10549d921096SMatt Spinler std::vector<uint8_t> out;
10559d921096SMatt Spinler
10569d921096SMatt Spinler for (const auto& line : lines)
10579d921096SMatt Spinler {
10589d921096SMatt Spinler out.insert(out.end(), line.begin(), line.end());
10599d921096SMatt Spinler
10609d921096SMatt Spinler if (out.back() != '\n')
10619d921096SMatt Spinler {
10629d921096SMatt Spinler out.push_back('\n');
10639d921096SMatt Spinler }
10649d921096SMatt Spinler }
10659d921096SMatt Spinler
10669d921096SMatt Spinler return out;
10679d921096SMatt Spinler }
10689d921096SMatt Spinler
addDIMMInfo(const std::string & locationCode,const std::vector<std::uint8_t> & diPropVal,nlohmann::json & adSysInfoData)1069d8ae618aSArya K Padman void addDIMMInfo(const std::string& locationCode,
1070d8ae618aSArya K Padman const std::vector<std::uint8_t>& diPropVal,
1071d8ae618aSArya K Padman nlohmann::json& adSysInfoData)
1072d8ae618aSArya K Padman {
1073d8ae618aSArya K Padman nlohmann::json dimmInfoObj;
1074d8ae618aSArya K Padman dimmInfoObj["Location Code"] = locationCode;
1075d8ae618aSArya K Padman std::ranges::transform(
1076d8ae618aSArya K Padman diPropVal, std::back_inserter(dimmInfoObj["DRAM Manufacturer ID"]),
1077d8ae618aSArya K Padman [](const auto& diPropEachByte) {
1078d8ae618aSArya K Padman return std::format("{:#04x}", diPropEachByte);
1079d8ae618aSArya K Padman });
1080d8ae618aSArya K Padman adSysInfoData["DIMMs Additional Info"] += dimmInfoObj;
1081d8ae618aSArya K Padman }
1082d8ae618aSArya K Padman
1083c7c3e402SMatt Spinler } // namespace util
1084c7c3e402SMatt Spinler
1085cb6b059eSMatt Spinler } // namespace pels
1086cb6b059eSMatt Spinler } // namespace openpower
1087