xref: /openbmc/phosphor-logging/extensions/openpower-pels/pel.cpp (revision 25291157927273a4ac459c6479c1d3090ddc6a16)
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