blob: c4156a842db23914a4d48d97862976b0a2d798fc [file] [log] [blame]
Matt Spinlercb6b0592019-07-16 15:58:51 -05001#include "pel.hpp"
2
3#include "bcd_time.hpp"
Matt Spinleraa659472019-10-23 09:26:48 -05004#include "failing_mtms.hpp"
Aatir186ce8c2019-10-20 15:13:39 -05005#include "hexdump.hpp"
Matt Spinlercb6b0592019-07-16 15:58:51 -05006#include "log_id.hpp"
Aatir186ce8c2019-10-20 15:13:39 -05007#include "pel_values.hpp"
Matt Spinler131870c2019-09-25 13:29:04 -05008#include "section_factory.hpp"
Matt Spinlerbd716f02019-10-15 10:54:11 -05009#include "src.hpp"
Matt Spinlercb6b0592019-07-16 15:58:51 -050010#include "stream.hpp"
Matt Spinlerafa857c2019-10-24 13:03:46 -050011#include "user_data_formats.hpp"
Matt Spinlercb6b0592019-07-16 15:58:51 -050012
Aatir186ce8c2019-10-20 15:13:39 -050013#include <iostream>
Matt Spinler07eefc52019-09-26 11:18:26 -050014#include <phosphor-logging/log.hpp>
15
Matt Spinlercb6b0592019-07-16 15:58:51 -050016namespace openpower
17{
18namespace pels
19{
Matt Spinlerb8323632019-09-20 15:11:04 -050020namespace message = openpower::pels::message;
Aatir186ce8c2019-10-20 15:13:39 -050021namespace pv = openpower::pels::pel_values;
Matt Spinlerb8323632019-09-20 15:11:04 -050022
23PEL::PEL(const message::Entry& entry, uint32_t obmcLogID, uint64_t timestamp,
Matt Spinlerbd716f02019-10-15 10:54:11 -050024 phosphor::logging::Entry::Level severity,
Matt Spinleraa659472019-10-23 09:26:48 -050025 const AdditionalData& additionalData,
26 const DataInterfaceBase& dataIface)
Matt Spinlerb8323632019-09-20 15:11:04 -050027{
28 _ph = std::make_unique<PrivateHeader>(entry.componentID, obmcLogID,
29 timestamp);
30 _uh = std::make_unique<UserHeader>(entry, severity);
31
Matt Spinlerbd716f02019-10-15 10:54:11 -050032 auto src = std::make_unique<SRC>(entry, additionalData);
33 _optionalSections.push_back(std::move(src));
Matt Spinlerb8323632019-09-20 15:11:04 -050034
Matt Spinleraa659472019-10-23 09:26:48 -050035 auto mtms = std::make_unique<FailingMTMS>(dataIface);
36 _optionalSections.push_back(std::move(mtms));
Matt Spinlerbd716f02019-10-15 10:54:11 -050037
Matt Spinlerafa857c2019-10-24 13:03:46 -050038 if (!additionalData.empty())
39 {
40 auto ud = util::makeADUserDataSection(additionalData);
41 _optionalSections.push_back(std::move(ud));
42 }
43
Matt Spinler97d19b42019-10-29 11:34:03 -050044 _ph->setSectionCount(2 + _optionalSections.size());
Matt Spinlerb8323632019-09-20 15:11:04 -050045}
Matt Spinlercb6b0592019-07-16 15:58:51 -050046
Matt Spinler07eefc52019-09-26 11:18:26 -050047PEL::PEL(std::vector<uint8_t>& data) : PEL(data, 0)
Matt Spinlercb6b0592019-07-16 15:58:51 -050048{
49}
50
Matt Spinler07eefc52019-09-26 11:18:26 -050051PEL::PEL(std::vector<uint8_t>& data, uint32_t obmcLogID)
Matt Spinlercb6b0592019-07-16 15:58:51 -050052{
Matt Spinler07eefc52019-09-26 11:18:26 -050053 populateFromRawData(data, obmcLogID);
Matt Spinlercb6b0592019-07-16 15:58:51 -050054}
55
Matt Spinler07eefc52019-09-26 11:18:26 -050056void PEL::populateFromRawData(std::vector<uint8_t>& data, uint32_t obmcLogID)
Matt Spinlercb6b0592019-07-16 15:58:51 -050057{
Matt Spinler07eefc52019-09-26 11:18:26 -050058 Stream pelData{data};
Matt Spinlercb6b0592019-07-16 15:58:51 -050059 _ph = std::make_unique<PrivateHeader>(pelData);
60 if (obmcLogID != 0)
61 {
Matt Spinler97d19b42019-10-29 11:34:03 -050062 _ph->setOBMCLogID(obmcLogID);
Matt Spinlercb6b0592019-07-16 15:58:51 -050063 }
64
65 _uh = std::make_unique<UserHeader>(pelData);
Matt Spinler131870c2019-09-25 13:29:04 -050066
67 // Use the section factory to create the rest of the objects
68 for (size_t i = 2; i < _ph->sectionCount(); i++)
69 {
70 auto section = section_factory::create(pelData);
71 _optionalSections.push_back(std::move(section));
72 }
Matt Spinlercb6b0592019-07-16 15:58:51 -050073}
74
75bool PEL::valid() const
76{
77 bool valid = _ph->valid();
78
79 if (valid)
80 {
81 valid = _uh->valid();
82 }
83
Matt Spinler131870c2019-09-25 13:29:04 -050084 if (valid)
85 {
86 if (!std::all_of(_optionalSections.begin(), _optionalSections.end(),
87 [](const auto& section) { return section->valid(); }))
88 {
89 valid = false;
90 }
91 }
92
Matt Spinlercb6b0592019-07-16 15:58:51 -050093 return valid;
94}
95
96void PEL::setCommitTime()
97{
98 auto now = std::chrono::system_clock::now();
Matt Spinler97d19b42019-10-29 11:34:03 -050099 _ph->setCommitTimestamp(getBCDTime(now));
Matt Spinlercb6b0592019-07-16 15:58:51 -0500100}
101
102void PEL::assignID()
103{
Matt Spinler97d19b42019-10-29 11:34:03 -0500104 _ph->setID(generatePELID());
Matt Spinlercb6b0592019-07-16 15:58:51 -0500105}
106
107void PEL::flatten(std::vector<uint8_t>& pelBuffer)
108{
109 Stream pelData{pelBuffer};
Matt Spinlerb8323632019-09-20 15:11:04 -0500110
Matt Spinler07eefc52019-09-26 11:18:26 -0500111 if (!valid())
Matt Spinlercb6b0592019-07-16 15:58:51 -0500112 {
Matt Spinler07eefc52019-09-26 11:18:26 -0500113 using namespace phosphor::logging;
114 log<level::WARNING>("Unflattening an invalid PEL");
Matt Spinlercb6b0592019-07-16 15:58:51 -0500115 }
116
Matt Spinler07eefc52019-09-26 11:18:26 -0500117 _ph->flatten(pelData);
Matt Spinlerb8323632019-09-20 15:11:04 -0500118 _uh->flatten(pelData);
Matt Spinler07eefc52019-09-26 11:18:26 -0500119
120 for (auto& section : _optionalSections)
121 {
122 section->flatten(pelData);
123 }
Matt Spinlercb6b0592019-07-16 15:58:51 -0500124}
125
126std::vector<uint8_t> PEL::data()
127{
Matt Spinler07eefc52019-09-26 11:18:26 -0500128 std::vector<uint8_t> pelData;
129 flatten(pelData);
130 return pelData;
Matt Spinlercb6b0592019-07-16 15:58:51 -0500131}
132
Matt Spinlerbd716f02019-10-15 10:54:11 -0500133std::optional<SRC*> PEL::primarySRC() const
134{
135 auto src = std::find_if(
136 _optionalSections.begin(), _optionalSections.end(), [](auto& section) {
137 return section->header().id ==
138 static_cast<uint16_t>(SectionID::primarySRC);
139 });
140 if (src != _optionalSections.end())
141 {
142 return static_cast<SRC*>(src->get());
143 }
144
145 return std::nullopt;
146}
147
Matt Spinlerafa857c2019-10-24 13:03:46 -0500148namespace util
149{
150
151std::unique_ptr<UserData> makeADUserDataSection(const AdditionalData& ad)
152{
153 assert(!ad.empty());
154 nlohmann::json json;
155
156 // Remove the 'ESEL' entry, as it contains a full PEL in the value.
157 if (ad.getValue("ESEL"))
158 {
159 auto newAD = ad;
160 newAD.remove("ESEL");
161 json = newAD.toJSON();
162 }
163 else
164 {
165 json = ad.toJSON();
166 }
167
168 auto jsonString = json.dump();
169 std::vector<uint8_t> jsonData(jsonString.begin(), jsonString.end());
170
171 return std::make_unique<UserData>(
172 static_cast<uint16_t>(ComponentID::phosphorLogging),
173 static_cast<uint8_t>(UserDataFormat::json),
174 static_cast<uint8_t>(UserDataFormatVersion::json), jsonData);
175}
176
177} // namespace util
Aatir186ce8c2019-10-20 15:13:39 -0500178void PEL::printSectionInJSON(Section& section, std::string& buf) const
179{
180 char tmpB[5];
181 if (section.valid())
182 {
183 uint8_t id[] = {static_cast<uint8_t>(section.header().id >> 8),
184 static_cast<uint8_t>(section.header().id)};
185 sprintf(tmpB, "%c%c", id[0], id[1]);
186 std::string sectionID(tmpB);
187 std::string sectionName = pv::sectionTitles.count(sectionID)
188 ? pv::sectionTitles.at(sectionID)
189 : "Unknown Section";
190 buf += "\n\"" + sectionName + "\":[\n ";
191 std::vector<uint8_t> data;
192 Stream s{data};
193 section.flatten(s);
194 std::string dstr = dumpHex(std::data(data), data.size());
195 buf += dstr + "\n],\n";
196 }
197 else
198 {
199 buf += "\n\"Invalid Section \":[\n invalid \n],\n";
200 }
201}
202
203void PEL::toJSON()
204{
205 std::string buf = "{";
206 printSectionInJSON(*(_ph.get()), buf);
207 printSectionInJSON(*(_uh.get()), buf);
208 for (auto& section : this->optionalSections())
209 {
210 printSectionInJSON(*(section.get()), buf);
211 }
212 buf += "}";
213 std::size_t found = buf.rfind(",");
214 if (found != std::string::npos)
215 buf.replace(found, 1, "");
216 std::cout << buf << std::endl;
217}
Matt Spinlercb6b0592019-07-16 15:58:51 -0500218} // namespace pels
219} // namespace openpower