blob: 1ba5c97a5e5ff63928eb5e951143804a79a95c24 [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"
Aatir186ce8c2019-10-20 15:13:39 -050022#include "pel_values.hpp"
Matt Spinler131870c2019-09-25 13:29:04 -050023#include "section_factory.hpp"
Matt Spinlerbd716f02019-10-15 10:54:11 -050024#include "src.hpp"
Matt Spinlercb6b0592019-07-16 15:58:51 -050025#include "stream.hpp"
Matt Spinlerafa857c2019-10-24 13:03:46 -050026#include "user_data_formats.hpp"
Matt Spinlercb6b0592019-07-16 15:58:51 -050027
Aatir186ce8c2019-10-20 15:13:39 -050028#include <iostream>
Matt Spinler07eefc52019-09-26 11:18:26 -050029#include <phosphor-logging/log.hpp>
30
Matt Spinlercb6b0592019-07-16 15:58:51 -050031namespace openpower
32{
33namespace pels
34{
Matt Spinlerb8323632019-09-20 15:11:04 -050035namespace message = openpower::pels::message;
Aatir186ce8c2019-10-20 15:13:39 -050036namespace pv = openpower::pels::pel_values;
Matt Spinlerb8323632019-09-20 15:11:04 -050037
38PEL::PEL(const message::Entry& entry, uint32_t obmcLogID, uint64_t timestamp,
Matt Spinlerbd716f02019-10-15 10:54:11 -050039 phosphor::logging::Entry::Level severity,
Matt Spinleraa659472019-10-23 09:26:48 -050040 const AdditionalData& additionalData,
41 const DataInterfaceBase& dataIface)
Matt Spinlerb8323632019-09-20 15:11:04 -050042{
43 _ph = std::make_unique<PrivateHeader>(entry.componentID, obmcLogID,
44 timestamp);
45 _uh = std::make_unique<UserHeader>(entry, severity);
46
Matt Spinlerbd716f02019-10-15 10:54:11 -050047 auto src = std::make_unique<SRC>(entry, additionalData);
48 _optionalSections.push_back(std::move(src));
Matt Spinlerb8323632019-09-20 15:11:04 -050049
Matt Spinleraa659472019-10-23 09:26:48 -050050 auto mtms = std::make_unique<FailingMTMS>(dataIface);
51 _optionalSections.push_back(std::move(mtms));
Matt Spinlerbd716f02019-10-15 10:54:11 -050052
Matt Spinlerafa857c2019-10-24 13:03:46 -050053 if (!additionalData.empty())
54 {
55 auto ud = util::makeADUserDataSection(additionalData);
56 _optionalSections.push_back(std::move(ud));
57 }
58
Matt Spinler97d19b42019-10-29 11:34:03 -050059 _ph->setSectionCount(2 + _optionalSections.size());
Matt Spinlerb8323632019-09-20 15:11:04 -050060}
Matt Spinlercb6b0592019-07-16 15:58:51 -050061
Matt Spinler07eefc52019-09-26 11:18:26 -050062PEL::PEL(std::vector<uint8_t>& data) : PEL(data, 0)
Matt Spinlercb6b0592019-07-16 15:58:51 -050063{
64}
65
Matt Spinler07eefc52019-09-26 11:18:26 -050066PEL::PEL(std::vector<uint8_t>& data, uint32_t obmcLogID)
Matt Spinlercb6b0592019-07-16 15:58:51 -050067{
Matt Spinler07eefc52019-09-26 11:18:26 -050068 populateFromRawData(data, obmcLogID);
Matt Spinlercb6b0592019-07-16 15:58:51 -050069}
70
Matt Spinler07eefc52019-09-26 11:18:26 -050071void PEL::populateFromRawData(std::vector<uint8_t>& data, uint32_t obmcLogID)
Matt Spinlercb6b0592019-07-16 15:58:51 -050072{
Matt Spinler07eefc52019-09-26 11:18:26 -050073 Stream pelData{data};
Matt Spinlercb6b0592019-07-16 15:58:51 -050074 _ph = std::make_unique<PrivateHeader>(pelData);
75 if (obmcLogID != 0)
76 {
Matt Spinler97d19b42019-10-29 11:34:03 -050077 _ph->setOBMCLogID(obmcLogID);
Matt Spinlercb6b0592019-07-16 15:58:51 -050078 }
79
80 _uh = std::make_unique<UserHeader>(pelData);
Matt Spinler131870c2019-09-25 13:29:04 -050081
82 // Use the section factory to create the rest of the objects
83 for (size_t i = 2; i < _ph->sectionCount(); i++)
84 {
85 auto section = section_factory::create(pelData);
86 _optionalSections.push_back(std::move(section));
87 }
Matt Spinlercb6b0592019-07-16 15:58:51 -050088}
89
90bool PEL::valid() const
91{
92 bool valid = _ph->valid();
93
94 if (valid)
95 {
96 valid = _uh->valid();
97 }
98
Matt Spinler131870c2019-09-25 13:29:04 -050099 if (valid)
100 {
101 if (!std::all_of(_optionalSections.begin(), _optionalSections.end(),
102 [](const auto& section) { return section->valid(); }))
103 {
104 valid = false;
105 }
106 }
107
Matt Spinlercb6b0592019-07-16 15:58:51 -0500108 return valid;
109}
110
111void PEL::setCommitTime()
112{
113 auto now = std::chrono::system_clock::now();
Matt Spinler97d19b42019-10-29 11:34:03 -0500114 _ph->setCommitTimestamp(getBCDTime(now));
Matt Spinlercb6b0592019-07-16 15:58:51 -0500115}
116
117void PEL::assignID()
118{
Matt Spinler97d19b42019-10-29 11:34:03 -0500119 _ph->setID(generatePELID());
Matt Spinlercb6b0592019-07-16 15:58:51 -0500120}
121
122void PEL::flatten(std::vector<uint8_t>& pelBuffer)
123{
124 Stream pelData{pelBuffer};
Matt Spinlerb8323632019-09-20 15:11:04 -0500125
Matt Spinler07eefc52019-09-26 11:18:26 -0500126 if (!valid())
Matt Spinlercb6b0592019-07-16 15:58:51 -0500127 {
Matt Spinler07eefc52019-09-26 11:18:26 -0500128 using namespace phosphor::logging;
129 log<level::WARNING>("Unflattening an invalid PEL");
Matt Spinlercb6b0592019-07-16 15:58:51 -0500130 }
131
Matt Spinler07eefc52019-09-26 11:18:26 -0500132 _ph->flatten(pelData);
Matt Spinlerb8323632019-09-20 15:11:04 -0500133 _uh->flatten(pelData);
Matt Spinler07eefc52019-09-26 11:18:26 -0500134
135 for (auto& section : _optionalSections)
136 {
137 section->flatten(pelData);
138 }
Matt Spinlercb6b0592019-07-16 15:58:51 -0500139}
140
141std::vector<uint8_t> PEL::data()
142{
Matt Spinler07eefc52019-09-26 11:18:26 -0500143 std::vector<uint8_t> pelData;
144 flatten(pelData);
145 return pelData;
Matt Spinlercb6b0592019-07-16 15:58:51 -0500146}
147
Matt Spinlerbd716f02019-10-15 10:54:11 -0500148std::optional<SRC*> PEL::primarySRC() const
149{
150 auto src = std::find_if(
151 _optionalSections.begin(), _optionalSections.end(), [](auto& section) {
152 return section->header().id ==
153 static_cast<uint16_t>(SectionID::primarySRC);
154 });
155 if (src != _optionalSections.end())
156 {
157 return static_cast<SRC*>(src->get());
158 }
159
160 return std::nullopt;
161}
162
Matt Spinlerafa857c2019-10-24 13:03:46 -0500163namespace util
164{
165
166std::unique_ptr<UserData> makeADUserDataSection(const AdditionalData& ad)
167{
168 assert(!ad.empty());
169 nlohmann::json json;
170
171 // Remove the 'ESEL' entry, as it contains a full PEL in the value.
172 if (ad.getValue("ESEL"))
173 {
174 auto newAD = ad;
175 newAD.remove("ESEL");
176 json = newAD.toJSON();
177 }
178 else
179 {
180 json = ad.toJSON();
181 }
182
183 auto jsonString = json.dump();
184 std::vector<uint8_t> jsonData(jsonString.begin(), jsonString.end());
185
186 return std::make_unique<UserData>(
187 static_cast<uint16_t>(ComponentID::phosphorLogging),
188 static_cast<uint8_t>(UserDataFormat::json),
189 static_cast<uint8_t>(UserDataFormatVersion::json), jsonData);
190}
191
192} // namespace util
Aatir186ce8c2019-10-20 15:13:39 -0500193void PEL::printSectionInJSON(Section& section, std::string& buf) const
194{
195 char tmpB[5];
196 if (section.valid())
197 {
198 uint8_t id[] = {static_cast<uint8_t>(section.header().id >> 8),
199 static_cast<uint8_t>(section.header().id)};
200 sprintf(tmpB, "%c%c", id[0], id[1]);
201 std::string sectionID(tmpB);
202 std::string sectionName = pv::sectionTitles.count(sectionID)
203 ? pv::sectionTitles.at(sectionID)
204 : "Unknown Section";
205 buf += "\n\"" + sectionName + "\":[\n ";
206 std::vector<uint8_t> data;
207 Stream s{data};
208 section.flatten(s);
209 std::string dstr = dumpHex(std::data(data), data.size());
210 buf += dstr + "\n],\n";
211 }
212 else
213 {
214 buf += "\n\"Invalid Section \":[\n invalid \n],\n";
215 }
216}
217
218void PEL::toJSON()
219{
220 std::string buf = "{";
221 printSectionInJSON(*(_ph.get()), buf);
222 printSectionInJSON(*(_uh.get()), buf);
223 for (auto& section : this->optionalSections())
224 {
225 printSectionInJSON(*(section.get()), buf);
226 }
227 buf += "}";
228 std::size_t found = buf.rfind(",");
229 if (found != std::string::npos)
230 buf.replace(found, 1, "");
231 std::cout << buf << std::endl;
232}
Matt Spinlercb6b0592019-07-16 15:58:51 -0500233} // namespace pels
234} // namespace openpower