blob: 262865f858a39dbc8f74e3945a550bade12f47ed [file] [log] [blame]
Matt Spinler711d51d2019-11-06 09:36:51 -06001/**
2 * Copyright © 2019 IBM Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Matt Spinlercb6b0592019-07-16 15:58:51 -050016#include "pel.hpp"
17
18#include "bcd_time.hpp"
Matt Spinlerc63e2e82019-12-02 15:50:12 -060019#include "extended_user_header.hpp"
Matt Spinleraa659472019-10-23 09:26:48 -050020#include "failing_mtms.hpp"
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +080021#include "json_utils.hpp"
Matt Spinlercb6b0592019-07-16 15:58:51 -050022#include "log_id.hpp"
Matt Spinlerf1e85e22019-11-01 11:31:31 -050023#include "pel_rules.hpp"
Aatir186ce8c2019-10-20 15:13:39 -050024#include "pel_values.hpp"
Matt Spinler131870c2019-09-25 13:29:04 -050025#include "section_factory.hpp"
Matt Spinlerbd716f02019-10-15 10:54:11 -050026#include "src.hpp"
Matt Spinlercb6b0592019-07-16 15:58:51 -050027#include "stream.hpp"
Matt Spinlerafa857c2019-10-24 13:03:46 -050028#include "user_data_formats.hpp"
Matt Spinlercb6b0592019-07-16 15:58:51 -050029
Aatir186ce8c2019-10-20 15:13:39 -050030#include <iostream>
Matt Spinler07eefc52019-09-26 11:18:26 -050031#include <phosphor-logging/log.hpp>
32
Matt Spinlercb6b0592019-07-16 15:58:51 -050033namespace openpower
34{
35namespace pels
36{
Matt Spinlerb8323632019-09-20 15:11:04 -050037namespace message = openpower::pels::message;
Aatir186ce8c2019-10-20 15:13:39 -050038namespace pv = openpower::pels::pel_values;
Matt Spinlerb8323632019-09-20 15:11:04 -050039
40PEL::PEL(const message::Entry& entry, uint32_t obmcLogID, uint64_t timestamp,
Matt Spinlerbd716f02019-10-15 10:54:11 -050041 phosphor::logging::Entry::Level severity,
Matt Spinleraa659472019-10-23 09:26:48 -050042 const AdditionalData& additionalData,
43 const DataInterfaceBase& dataIface)
Matt Spinlerb8323632019-09-20 15:11:04 -050044{
45 _ph = std::make_unique<PrivateHeader>(entry.componentID, obmcLogID,
46 timestamp);
47 _uh = std::make_unique<UserHeader>(entry, severity);
48
Matt Spinlerbd716f02019-10-15 10:54:11 -050049 auto src = std::make_unique<SRC>(entry, additionalData);
Matt Spinlerc63e2e82019-12-02 15:50:12 -060050
51 auto euh = std::make_unique<ExtendedUserHeader>(dataIface, entry, *src);
52
Matt Spinlerbd716f02019-10-15 10:54:11 -050053 _optionalSections.push_back(std::move(src));
Matt Spinlerc63e2e82019-12-02 15:50:12 -060054 _optionalSections.push_back(std::move(euh));
Matt Spinlerb8323632019-09-20 15:11:04 -050055
Matt Spinleraa659472019-10-23 09:26:48 -050056 auto mtms = std::make_unique<FailingMTMS>(dataIface);
57 _optionalSections.push_back(std::move(mtms));
Matt Spinlerbd716f02019-10-15 10:54:11 -050058
Matt Spinlerafa857c2019-10-24 13:03:46 -050059 if (!additionalData.empty())
60 {
61 auto ud = util::makeADUserDataSection(additionalData);
62 _optionalSections.push_back(std::move(ud));
63 }
64
Matt Spinler97d19b42019-10-29 11:34:03 -050065 _ph->setSectionCount(2 + _optionalSections.size());
Matt Spinlerf1e85e22019-11-01 11:31:31 -050066
67 checkRulesAndFix();
Matt Spinlerb8323632019-09-20 15:11:04 -050068}
Matt Spinlercb6b0592019-07-16 15:58:51 -050069
Matt Spinler07eefc52019-09-26 11:18:26 -050070PEL::PEL(std::vector<uint8_t>& data) : PEL(data, 0)
Matt Spinlercb6b0592019-07-16 15:58:51 -050071{
72}
73
Matt Spinler07eefc52019-09-26 11:18:26 -050074PEL::PEL(std::vector<uint8_t>& data, uint32_t obmcLogID)
Matt Spinlercb6b0592019-07-16 15:58:51 -050075{
Matt Spinler07eefc52019-09-26 11:18:26 -050076 populateFromRawData(data, obmcLogID);
Matt Spinlercb6b0592019-07-16 15:58:51 -050077}
78
Matt Spinler07eefc52019-09-26 11:18:26 -050079void PEL::populateFromRawData(std::vector<uint8_t>& data, uint32_t obmcLogID)
Matt Spinlercb6b0592019-07-16 15:58:51 -050080{
Matt Spinler07eefc52019-09-26 11:18:26 -050081 Stream pelData{data};
Matt Spinlercb6b0592019-07-16 15:58:51 -050082 _ph = std::make_unique<PrivateHeader>(pelData);
83 if (obmcLogID != 0)
84 {
Matt Spinler97d19b42019-10-29 11:34:03 -050085 _ph->setOBMCLogID(obmcLogID);
Matt Spinlercb6b0592019-07-16 15:58:51 -050086 }
87
88 _uh = std::make_unique<UserHeader>(pelData);
Matt Spinler131870c2019-09-25 13:29:04 -050089
90 // Use the section factory to create the rest of the objects
91 for (size_t i = 2; i < _ph->sectionCount(); i++)
92 {
93 auto section = section_factory::create(pelData);
94 _optionalSections.push_back(std::move(section));
95 }
Matt Spinlercb6b0592019-07-16 15:58:51 -050096}
97
98bool PEL::valid() const
99{
100 bool valid = _ph->valid();
101
102 if (valid)
103 {
104 valid = _uh->valid();
105 }
106
Matt Spinler131870c2019-09-25 13:29:04 -0500107 if (valid)
108 {
109 if (!std::all_of(_optionalSections.begin(), _optionalSections.end(),
110 [](const auto& section) { return section->valid(); }))
111 {
112 valid = false;
113 }
114 }
115
Matt Spinlercb6b0592019-07-16 15:58:51 -0500116 return valid;
117}
118
119void PEL::setCommitTime()
120{
121 auto now = std::chrono::system_clock::now();
Matt Spinler97d19b42019-10-29 11:34:03 -0500122 _ph->setCommitTimestamp(getBCDTime(now));
Matt Spinlercb6b0592019-07-16 15:58:51 -0500123}
124
125void PEL::assignID()
126{
Matt Spinler97d19b42019-10-29 11:34:03 -0500127 _ph->setID(generatePELID());
Matt Spinlercb6b0592019-07-16 15:58:51 -0500128}
129
Matt Spinler06885452019-11-06 10:35:42 -0600130void PEL::flatten(std::vector<uint8_t>& pelBuffer) const
Matt Spinlercb6b0592019-07-16 15:58:51 -0500131{
132 Stream pelData{pelBuffer};
Matt Spinlerb8323632019-09-20 15:11:04 -0500133
Matt Spinler07eefc52019-09-26 11:18:26 -0500134 if (!valid())
Matt Spinlercb6b0592019-07-16 15:58:51 -0500135 {
Matt Spinler07eefc52019-09-26 11:18:26 -0500136 using namespace phosphor::logging;
137 log<level::WARNING>("Unflattening an invalid PEL");
Matt Spinlercb6b0592019-07-16 15:58:51 -0500138 }
139
Matt Spinler07eefc52019-09-26 11:18:26 -0500140 _ph->flatten(pelData);
Matt Spinlerb8323632019-09-20 15:11:04 -0500141 _uh->flatten(pelData);
Matt Spinler07eefc52019-09-26 11:18:26 -0500142
143 for (auto& section : _optionalSections)
144 {
145 section->flatten(pelData);
146 }
Matt Spinlercb6b0592019-07-16 15:58:51 -0500147}
148
Matt Spinler06885452019-11-06 10:35:42 -0600149std::vector<uint8_t> PEL::data() const
Matt Spinlercb6b0592019-07-16 15:58:51 -0500150{
Matt Spinler07eefc52019-09-26 11:18:26 -0500151 std::vector<uint8_t> pelData;
152 flatten(pelData);
153 return pelData;
Matt Spinlercb6b0592019-07-16 15:58:51 -0500154}
155
Matt Spinlerbd716f02019-10-15 10:54:11 -0500156std::optional<SRC*> PEL::primarySRC() const
157{
158 auto src = std::find_if(
159 _optionalSections.begin(), _optionalSections.end(), [](auto& section) {
160 return section->header().id ==
161 static_cast<uint16_t>(SectionID::primarySRC);
162 });
163 if (src != _optionalSections.end())
164 {
165 return static_cast<SRC*>(src->get());
166 }
167
168 return std::nullopt;
169}
170
Matt Spinlerf1e85e22019-11-01 11:31:31 -0500171void PEL::checkRulesAndFix()
172{
173 auto [actionFlags, eventType] =
174 pel_rules::check(_uh->actionFlags(), _uh->eventType(), _uh->severity());
175
176 _uh->setActionFlags(actionFlags);
177 _uh->setEventType(eventType);
178}
179
Matt Spinlerafa857c2019-10-24 13:03:46 -0500180namespace util
181{
182
183std::unique_ptr<UserData> makeADUserDataSection(const AdditionalData& ad)
184{
185 assert(!ad.empty());
186 nlohmann::json json;
187
188 // Remove the 'ESEL' entry, as it contains a full PEL in the value.
189 if (ad.getValue("ESEL"))
190 {
191 auto newAD = ad;
192 newAD.remove("ESEL");
193 json = newAD.toJSON();
194 }
195 else
196 {
197 json = ad.toJSON();
198 }
199
200 auto jsonString = json.dump();
201 std::vector<uint8_t> jsonData(jsonString.begin(), jsonString.end());
202
Matt Spinlerb466f782019-11-08 10:44:01 -0600203 // Pad to a 4 byte boundary
204 while ((jsonData.size() % 4) != 0)
205 {
206 jsonData.push_back(0);
207 }
208
Matt Spinlerafa857c2019-10-24 13:03:46 -0500209 return std::make_unique<UserData>(
210 static_cast<uint16_t>(ComponentID::phosphorLogging),
211 static_cast<uint8_t>(UserDataFormat::json),
212 static_cast<uint8_t>(UserDataFormatVersion::json), jsonData);
213}
214
215} // namespace util
Matt Spinler06885452019-11-06 10:35:42 -0600216
Matt Spinleracb7c102020-01-10 13:49:22 -0600217void PEL::printSectionInJSON(const Section& section, std::string& buf,
218 std::map<uint16_t, size_t>& pluralSections) const
Aatir186ce8c2019-10-20 15:13:39 -0500219{
220 char tmpB[5];
Aatir Manzurad0e0472019-10-07 13:18:37 -0500221 uint8_t id[] = {static_cast<uint8_t>(section.header().id >> 8),
222 static_cast<uint8_t>(section.header().id)};
223 sprintf(tmpB, "%c%c", id[0], id[1]);
224 std::string sectionID(tmpB);
225 std::string sectionName = pv::sectionTitles.count(sectionID)
226 ? pv::sectionTitles.at(sectionID)
227 : "Unknown Section";
Matt Spinleracb7c102020-01-10 13:49:22 -0600228
229 // Add a count if there are multiple of this type of section
230 auto count = pluralSections.find(section.header().id);
231 if (count != pluralSections.end())
232 {
233 sectionName += " " + std::to_string(count->second);
234 count->second++;
235 }
236
Aatir186ce8c2019-10-20 15:13:39 -0500237 if (section.valid())
238 {
Aatir Manzurad0e0472019-10-07 13:18:37 -0500239 auto json = section.getJSON();
240 if (json)
241 {
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800242 buf += "\n\"" + sectionName + "\": {\n";
243 buf += *json + "\n},\n";
Aatir Manzurad0e0472019-10-07 13:18:37 -0500244 }
245 else
246 {
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800247 buf += "\n\"" + sectionName + "\": [\n";
Aatir Manzurad0e0472019-10-07 13:18:37 -0500248 std::vector<uint8_t> data;
249 Stream s{data};
250 section.flatten(s);
251 std::string dstr = dumpHex(std::data(data), data.size());
252 buf += dstr + "],\n";
253 }
Aatir186ce8c2019-10-20 15:13:39 -0500254 }
255 else
256 {
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800257 buf += "\n\"Invalid Section\": [\n \"invalid\"\n],\n";
Aatir186ce8c2019-10-20 15:13:39 -0500258 }
259}
260
Matt Spinleracb7c102020-01-10 13:49:22 -0600261std::map<uint16_t, size_t> PEL::getPluralSections() const
262{
263 std::map<uint16_t, size_t> sectionCounts;
264
265 for (const auto& section : optionalSections())
266 {
267 if (sectionCounts.find(section->header().id) == sectionCounts.end())
268 {
269 sectionCounts[section->header().id] = 1;
270 }
271 else
272 {
273 sectionCounts[section->header().id]++;
274 }
275 }
276
277 std::map<uint16_t, size_t> sections;
278 for (const auto& [id, count] : sectionCounts)
279 {
280 if (count > 1)
281 {
282 // Start with 0 here and printSectionInJSON()
283 // will increment it as it goes.
284 sections.emplace(id, 0);
285 }
286 }
287
288 return sections;
289}
290
Matt Spinler06885452019-11-06 10:35:42 -0600291void PEL::toJSON() const
Aatir186ce8c2019-10-20 15:13:39 -0500292{
Matt Spinleracb7c102020-01-10 13:49:22 -0600293 auto sections = getPluralSections();
294
Aatir186ce8c2019-10-20 15:13:39 -0500295 std::string buf = "{";
Matt Spinleracb7c102020-01-10 13:49:22 -0600296 printSectionInJSON(*(_ph.get()), buf, sections);
297 printSectionInJSON(*(_uh.get()), buf, sections);
Aatir186ce8c2019-10-20 15:13:39 -0500298 for (auto& section : this->optionalSections())
299 {
Matt Spinleracb7c102020-01-10 13:49:22 -0600300 printSectionInJSON(*(section.get()), buf, sections);
Aatir186ce8c2019-10-20 15:13:39 -0500301 }
302 buf += "}";
303 std::size_t found = buf.rfind(",");
304 if (found != std::string::npos)
305 buf.replace(found, 1, "");
306 std::cout << buf << std::endl;
307}
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800308
Matt Spinlercb6b0592019-07-16 15:58:51 -0500309} // namespace pels
310} // namespace openpower