blob: e006541207bc69a14772293499c15187f2cccfe6 [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 Spinleraa659472019-10-23 09:26:48 -050019#include "failing_mtms.hpp"
Aatir186ce8c2019-10-20 15:13:39 -050020#include "hexdump.hpp"
Matt Spinlercb6b0592019-07-16 15:58:51 -050021#include "log_id.hpp"
Matt Spinlerf1e85e22019-11-01 11:31:31 -050022#include "pel_rules.hpp"
Aatir186ce8c2019-10-20 15:13:39 -050023#include "pel_values.hpp"
Matt Spinler131870c2019-09-25 13:29:04 -050024#include "section_factory.hpp"
Matt Spinlerbd716f02019-10-15 10:54:11 -050025#include "src.hpp"
Matt Spinlercb6b0592019-07-16 15:58:51 -050026#include "stream.hpp"
Matt Spinlerafa857c2019-10-24 13:03:46 -050027#include "user_data_formats.hpp"
Matt Spinlercb6b0592019-07-16 15:58:51 -050028
Aatir186ce8c2019-10-20 15:13:39 -050029#include <iostream>
Matt Spinler07eefc52019-09-26 11:18:26 -050030#include <phosphor-logging/log.hpp>
31
Matt Spinlercb6b0592019-07-16 15:58:51 -050032namespace openpower
33{
34namespace pels
35{
Matt Spinlerb8323632019-09-20 15:11:04 -050036namespace message = openpower::pels::message;
Aatir186ce8c2019-10-20 15:13:39 -050037namespace pv = openpower::pels::pel_values;
Matt Spinlerb8323632019-09-20 15:11:04 -050038
39PEL::PEL(const message::Entry& entry, uint32_t obmcLogID, uint64_t timestamp,
Matt Spinlerbd716f02019-10-15 10:54:11 -050040 phosphor::logging::Entry::Level severity,
Matt Spinleraa659472019-10-23 09:26:48 -050041 const AdditionalData& additionalData,
42 const DataInterfaceBase& dataIface)
Matt Spinlerb8323632019-09-20 15:11:04 -050043{
44 _ph = std::make_unique<PrivateHeader>(entry.componentID, obmcLogID,
45 timestamp);
46 _uh = std::make_unique<UserHeader>(entry, severity);
47
Matt Spinlerbd716f02019-10-15 10:54:11 -050048 auto src = std::make_unique<SRC>(entry, additionalData);
49 _optionalSections.push_back(std::move(src));
Matt Spinlerb8323632019-09-20 15:11:04 -050050
Matt Spinleraa659472019-10-23 09:26:48 -050051 auto mtms = std::make_unique<FailingMTMS>(dataIface);
52 _optionalSections.push_back(std::move(mtms));
Matt Spinlerbd716f02019-10-15 10:54:11 -050053
Matt Spinlerafa857c2019-10-24 13:03:46 -050054 if (!additionalData.empty())
55 {
56 auto ud = util::makeADUserDataSection(additionalData);
57 _optionalSections.push_back(std::move(ud));
58 }
59
Matt Spinler97d19b42019-10-29 11:34:03 -050060 _ph->setSectionCount(2 + _optionalSections.size());
Matt Spinlerf1e85e22019-11-01 11:31:31 -050061
62 checkRulesAndFix();
Matt Spinlerb8323632019-09-20 15:11:04 -050063}
Matt Spinlercb6b0592019-07-16 15:58:51 -050064
Matt Spinler07eefc52019-09-26 11:18:26 -050065PEL::PEL(std::vector<uint8_t>& data) : PEL(data, 0)
Matt Spinlercb6b0592019-07-16 15:58:51 -050066{
67}
68
Matt Spinler07eefc52019-09-26 11:18:26 -050069PEL::PEL(std::vector<uint8_t>& data, uint32_t obmcLogID)
Matt Spinlercb6b0592019-07-16 15:58:51 -050070{
Matt Spinler07eefc52019-09-26 11:18:26 -050071 populateFromRawData(data, obmcLogID);
Matt Spinlercb6b0592019-07-16 15:58:51 -050072}
73
Matt Spinler07eefc52019-09-26 11:18:26 -050074void PEL::populateFromRawData(std::vector<uint8_t>& data, uint32_t obmcLogID)
Matt Spinlercb6b0592019-07-16 15:58:51 -050075{
Matt Spinler07eefc52019-09-26 11:18:26 -050076 Stream pelData{data};
Matt Spinlercb6b0592019-07-16 15:58:51 -050077 _ph = std::make_unique<PrivateHeader>(pelData);
78 if (obmcLogID != 0)
79 {
Matt Spinler97d19b42019-10-29 11:34:03 -050080 _ph->setOBMCLogID(obmcLogID);
Matt Spinlercb6b0592019-07-16 15:58:51 -050081 }
82
83 _uh = std::make_unique<UserHeader>(pelData);
Matt Spinler131870c2019-09-25 13:29:04 -050084
85 // Use the section factory to create the rest of the objects
86 for (size_t i = 2; i < _ph->sectionCount(); i++)
87 {
88 auto section = section_factory::create(pelData);
89 _optionalSections.push_back(std::move(section));
90 }
Matt Spinlercb6b0592019-07-16 15:58:51 -050091}
92
93bool PEL::valid() const
94{
95 bool valid = _ph->valid();
96
97 if (valid)
98 {
99 valid = _uh->valid();
100 }
101
Matt Spinler131870c2019-09-25 13:29:04 -0500102 if (valid)
103 {
104 if (!std::all_of(_optionalSections.begin(), _optionalSections.end(),
105 [](const auto& section) { return section->valid(); }))
106 {
107 valid = false;
108 }
109 }
110
Matt Spinlercb6b0592019-07-16 15:58:51 -0500111 return valid;
112}
113
114void PEL::setCommitTime()
115{
116 auto now = std::chrono::system_clock::now();
Matt Spinler97d19b42019-10-29 11:34:03 -0500117 _ph->setCommitTimestamp(getBCDTime(now));
Matt Spinlercb6b0592019-07-16 15:58:51 -0500118}
119
120void PEL::assignID()
121{
Matt Spinler97d19b42019-10-29 11:34:03 -0500122 _ph->setID(generatePELID());
Matt Spinlercb6b0592019-07-16 15:58:51 -0500123}
124
Matt Spinler06885452019-11-06 10:35:42 -0600125void PEL::flatten(std::vector<uint8_t>& pelBuffer) const
Matt Spinlercb6b0592019-07-16 15:58:51 -0500126{
127 Stream pelData{pelBuffer};
Matt Spinlerb8323632019-09-20 15:11:04 -0500128
Matt Spinler07eefc52019-09-26 11:18:26 -0500129 if (!valid())
Matt Spinlercb6b0592019-07-16 15:58:51 -0500130 {
Matt Spinler07eefc52019-09-26 11:18:26 -0500131 using namespace phosphor::logging;
132 log<level::WARNING>("Unflattening an invalid PEL");
Matt Spinlercb6b0592019-07-16 15:58:51 -0500133 }
134
Matt Spinler07eefc52019-09-26 11:18:26 -0500135 _ph->flatten(pelData);
Matt Spinlerb8323632019-09-20 15:11:04 -0500136 _uh->flatten(pelData);
Matt Spinler07eefc52019-09-26 11:18:26 -0500137
138 for (auto& section : _optionalSections)
139 {
140 section->flatten(pelData);
141 }
Matt Spinlercb6b0592019-07-16 15:58:51 -0500142}
143
Matt Spinler06885452019-11-06 10:35:42 -0600144std::vector<uint8_t> PEL::data() const
Matt Spinlercb6b0592019-07-16 15:58:51 -0500145{
Matt Spinler07eefc52019-09-26 11:18:26 -0500146 std::vector<uint8_t> pelData;
147 flatten(pelData);
148 return pelData;
Matt Spinlercb6b0592019-07-16 15:58:51 -0500149}
150
Matt Spinlerbd716f02019-10-15 10:54:11 -0500151std::optional<SRC*> PEL::primarySRC() const
152{
153 auto src = std::find_if(
154 _optionalSections.begin(), _optionalSections.end(), [](auto& section) {
155 return section->header().id ==
156 static_cast<uint16_t>(SectionID::primarySRC);
157 });
158 if (src != _optionalSections.end())
159 {
160 return static_cast<SRC*>(src->get());
161 }
162
163 return std::nullopt;
164}
165
Matt Spinlerf1e85e22019-11-01 11:31:31 -0500166void PEL::checkRulesAndFix()
167{
168 auto [actionFlags, eventType] =
169 pel_rules::check(_uh->actionFlags(), _uh->eventType(), _uh->severity());
170
171 _uh->setActionFlags(actionFlags);
172 _uh->setEventType(eventType);
173}
174
Matt Spinlerafa857c2019-10-24 13:03:46 -0500175namespace util
176{
177
178std::unique_ptr<UserData> makeADUserDataSection(const AdditionalData& ad)
179{
180 assert(!ad.empty());
181 nlohmann::json json;
182
183 // Remove the 'ESEL' entry, as it contains a full PEL in the value.
184 if (ad.getValue("ESEL"))
185 {
186 auto newAD = ad;
187 newAD.remove("ESEL");
188 json = newAD.toJSON();
189 }
190 else
191 {
192 json = ad.toJSON();
193 }
194
195 auto jsonString = json.dump();
196 std::vector<uint8_t> jsonData(jsonString.begin(), jsonString.end());
197
Matt Spinlerb466f782019-11-08 10:44:01 -0600198 // Pad to a 4 byte boundary
199 while ((jsonData.size() % 4) != 0)
200 {
201 jsonData.push_back(0);
202 }
203
Matt Spinlerafa857c2019-10-24 13:03:46 -0500204 return std::make_unique<UserData>(
205 static_cast<uint16_t>(ComponentID::phosphorLogging),
206 static_cast<uint8_t>(UserDataFormat::json),
207 static_cast<uint8_t>(UserDataFormatVersion::json), jsonData);
208}
209
210} // namespace util
Matt Spinler06885452019-11-06 10:35:42 -0600211
212void PEL::printSectionInJSON(const Section& section, std::string& buf) const
Aatir186ce8c2019-10-20 15:13:39 -0500213{
214 char tmpB[5];
Aatir Manzurad0e0472019-10-07 13:18:37 -0500215 uint8_t id[] = {static_cast<uint8_t>(section.header().id >> 8),
216 static_cast<uint8_t>(section.header().id)};
217 sprintf(tmpB, "%c%c", id[0], id[1]);
218 std::string sectionID(tmpB);
219 std::string sectionName = pv::sectionTitles.count(sectionID)
220 ? pv::sectionTitles.at(sectionID)
221 : "Unknown Section";
Aatir186ce8c2019-10-20 15:13:39 -0500222 if (section.valid())
223 {
Aatir Manzurad0e0472019-10-07 13:18:37 -0500224 auto json = section.getJSON();
225 if (json)
226 {
227 buf += "\n\"" + sectionName + "\":[\n ";
228 buf += *json + "\n],\n";
229 }
230 else
231 {
232 buf += "\n\"" + sectionName + "\":[\n ";
233 std::vector<uint8_t> data;
234 Stream s{data};
235 section.flatten(s);
236 std::string dstr = dumpHex(std::data(data), data.size());
237 buf += dstr + "],\n";
238 }
Aatir186ce8c2019-10-20 15:13:39 -0500239 }
240 else
241 {
242 buf += "\n\"Invalid Section \":[\n invalid \n],\n";
243 }
244}
245
Matt Spinler06885452019-11-06 10:35:42 -0600246void PEL::toJSON() const
Aatir186ce8c2019-10-20 15:13:39 -0500247{
248 std::string buf = "{";
249 printSectionInJSON(*(_ph.get()), buf);
250 printSectionInJSON(*(_uh.get()), buf);
251 for (auto& section : this->optionalSections())
252 {
253 printSectionInJSON(*(section.get()), buf);
254 }
255 buf += "}";
256 std::size_t found = buf.rfind(",");
257 if (found != std::string::npos)
258 buf.replace(found, 1, "");
259 std::cout << buf << std::endl;
260}
Matt Spinlercb6b0592019-07-16 15:58:51 -0500261} // namespace pels
262} // namespace openpower