blob: 0c05ac18bf32577790cf3c60ad1d8bb50e4126cf [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 Spinler4dcd3f42020-01-22 14:55:07 -060059 auto ud = util::makeSysInfoUserDataSection(additionalData, dataIface);
60 _optionalSections.push_back(std::move(ud));
61
Matt Spinlerafa857c2019-10-24 13:03:46 -050062 if (!additionalData.empty())
63 {
Matt Spinler4dcd3f42020-01-22 14:55:07 -060064 ud = util::makeADUserDataSection(additionalData);
Matt Spinler6d663822020-01-22 14:50:46 -060065
66 // To be safe, check there isn't too much data
67 if (size() + ud->header().size <= _maxPELSize)
68 {
69 _optionalSections.push_back(std::move(ud));
70 }
Matt Spinlerafa857c2019-10-24 13:03:46 -050071 }
72
Matt Spinler97d19b42019-10-29 11:34:03 -050073 _ph->setSectionCount(2 + _optionalSections.size());
Matt Spinlerf1e85e22019-11-01 11:31:31 -050074
75 checkRulesAndFix();
Matt Spinlerb8323632019-09-20 15:11:04 -050076}
Matt Spinlercb6b0592019-07-16 15:58:51 -050077
Matt Spinler07eefc52019-09-26 11:18:26 -050078PEL::PEL(std::vector<uint8_t>& data) : PEL(data, 0)
Matt Spinlercb6b0592019-07-16 15:58:51 -050079{
80}
81
Matt Spinler07eefc52019-09-26 11:18:26 -050082PEL::PEL(std::vector<uint8_t>& data, uint32_t obmcLogID)
Matt Spinlercb6b0592019-07-16 15:58:51 -050083{
Matt Spinler07eefc52019-09-26 11:18:26 -050084 populateFromRawData(data, obmcLogID);
Matt Spinlercb6b0592019-07-16 15:58:51 -050085}
86
Matt Spinler07eefc52019-09-26 11:18:26 -050087void PEL::populateFromRawData(std::vector<uint8_t>& data, uint32_t obmcLogID)
Matt Spinlercb6b0592019-07-16 15:58:51 -050088{
Matt Spinler07eefc52019-09-26 11:18:26 -050089 Stream pelData{data};
Matt Spinlercb6b0592019-07-16 15:58:51 -050090 _ph = std::make_unique<PrivateHeader>(pelData);
91 if (obmcLogID != 0)
92 {
Matt Spinler97d19b42019-10-29 11:34:03 -050093 _ph->setOBMCLogID(obmcLogID);
Matt Spinlercb6b0592019-07-16 15:58:51 -050094 }
95
96 _uh = std::make_unique<UserHeader>(pelData);
Matt Spinler131870c2019-09-25 13:29:04 -050097
98 // Use the section factory to create the rest of the objects
99 for (size_t i = 2; i < _ph->sectionCount(); i++)
100 {
101 auto section = section_factory::create(pelData);
102 _optionalSections.push_back(std::move(section));
103 }
Matt Spinlercb6b0592019-07-16 15:58:51 -0500104}
105
106bool PEL::valid() const
107{
108 bool valid = _ph->valid();
109
110 if (valid)
111 {
112 valid = _uh->valid();
113 }
114
Matt Spinler131870c2019-09-25 13:29:04 -0500115 if (valid)
116 {
117 if (!std::all_of(_optionalSections.begin(), _optionalSections.end(),
118 [](const auto& section) { return section->valid(); }))
119 {
120 valid = false;
121 }
122 }
123
Matt Spinlercb6b0592019-07-16 15:58:51 -0500124 return valid;
125}
126
127void PEL::setCommitTime()
128{
129 auto now = std::chrono::system_clock::now();
Matt Spinler97d19b42019-10-29 11:34:03 -0500130 _ph->setCommitTimestamp(getBCDTime(now));
Matt Spinlercb6b0592019-07-16 15:58:51 -0500131}
132
133void PEL::assignID()
134{
Matt Spinler97d19b42019-10-29 11:34:03 -0500135 _ph->setID(generatePELID());
Matt Spinlercb6b0592019-07-16 15:58:51 -0500136}
137
Matt Spinler06885452019-11-06 10:35:42 -0600138void PEL::flatten(std::vector<uint8_t>& pelBuffer) const
Matt Spinlercb6b0592019-07-16 15:58:51 -0500139{
140 Stream pelData{pelBuffer};
Matt Spinlerb8323632019-09-20 15:11:04 -0500141
Matt Spinler07eefc52019-09-26 11:18:26 -0500142 if (!valid())
Matt Spinlercb6b0592019-07-16 15:58:51 -0500143 {
Matt Spinler07eefc52019-09-26 11:18:26 -0500144 using namespace phosphor::logging;
145 log<level::WARNING>("Unflattening an invalid PEL");
Matt Spinlercb6b0592019-07-16 15:58:51 -0500146 }
147
Matt Spinler07eefc52019-09-26 11:18:26 -0500148 _ph->flatten(pelData);
Matt Spinlerb8323632019-09-20 15:11:04 -0500149 _uh->flatten(pelData);
Matt Spinler07eefc52019-09-26 11:18:26 -0500150
151 for (auto& section : _optionalSections)
152 {
153 section->flatten(pelData);
154 }
Matt Spinlercb6b0592019-07-16 15:58:51 -0500155}
156
Matt Spinler06885452019-11-06 10:35:42 -0600157std::vector<uint8_t> PEL::data() const
Matt Spinlercb6b0592019-07-16 15:58:51 -0500158{
Matt Spinler07eefc52019-09-26 11:18:26 -0500159 std::vector<uint8_t> pelData;
160 flatten(pelData);
161 return pelData;
Matt Spinlercb6b0592019-07-16 15:58:51 -0500162}
163
Matt Spinlerf1b46ff2020-01-22 14:10:04 -0600164size_t PEL::size() const
165{
166 size_t size = 0;
167
168 if (_ph)
169 {
170 size += _ph->header().size;
171 }
172
173 if (_uh)
174 {
175 size += _uh->header().size;
176 }
177
178 for (const auto& section : _optionalSections)
179 {
180 size += section->header().size;
181 }
182
183 return size;
184}
185
Matt Spinlerbd716f02019-10-15 10:54:11 -0500186std::optional<SRC*> PEL::primarySRC() const
187{
188 auto src = std::find_if(
189 _optionalSections.begin(), _optionalSections.end(), [](auto& section) {
190 return section->header().id ==
191 static_cast<uint16_t>(SectionID::primarySRC);
192 });
193 if (src != _optionalSections.end())
194 {
195 return static_cast<SRC*>(src->get());
196 }
197
198 return std::nullopt;
199}
200
Matt Spinlerf1e85e22019-11-01 11:31:31 -0500201void PEL::checkRulesAndFix()
202{
203 auto [actionFlags, eventType] =
204 pel_rules::check(_uh->actionFlags(), _uh->eventType(), _uh->severity());
205
206 _uh->setActionFlags(actionFlags);
207 _uh->setEventType(eventType);
208}
209
Matt Spinleracb7c102020-01-10 13:49:22 -0600210void PEL::printSectionInJSON(const Section& section, std::string& buf,
211 std::map<uint16_t, size_t>& pluralSections) const
Aatir186ce8c2019-10-20 15:13:39 -0500212{
213 char tmpB[5];
Aatir Manzurad0e0472019-10-07 13:18:37 -0500214 uint8_t id[] = {static_cast<uint8_t>(section.header().id >> 8),
215 static_cast<uint8_t>(section.header().id)};
216 sprintf(tmpB, "%c%c", id[0], id[1]);
217 std::string sectionID(tmpB);
218 std::string sectionName = pv::sectionTitles.count(sectionID)
219 ? pv::sectionTitles.at(sectionID)
220 : "Unknown Section";
Matt Spinleracb7c102020-01-10 13:49:22 -0600221
222 // Add a count if there are multiple of this type of section
223 auto count = pluralSections.find(section.header().id);
224 if (count != pluralSections.end())
225 {
226 sectionName += " " + std::to_string(count->second);
227 count->second++;
228 }
229
Aatir186ce8c2019-10-20 15:13:39 -0500230 if (section.valid())
231 {
Aatir Manzurad0e0472019-10-07 13:18:37 -0500232 auto json = section.getJSON();
233 if (json)
234 {
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800235 buf += "\n\"" + sectionName + "\": {\n";
236 buf += *json + "\n},\n";
Aatir Manzurad0e0472019-10-07 13:18:37 -0500237 }
238 else
239 {
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800240 buf += "\n\"" + sectionName + "\": [\n";
Aatir Manzurad0e0472019-10-07 13:18:37 -0500241 std::vector<uint8_t> data;
242 Stream s{data};
243 section.flatten(s);
244 std::string dstr = dumpHex(std::data(data), data.size());
245 buf += dstr + "],\n";
246 }
Aatir186ce8c2019-10-20 15:13:39 -0500247 }
248 else
249 {
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800250 buf += "\n\"Invalid Section\": [\n \"invalid\"\n],\n";
Aatir186ce8c2019-10-20 15:13:39 -0500251 }
252}
253
Matt Spinleracb7c102020-01-10 13:49:22 -0600254std::map<uint16_t, size_t> PEL::getPluralSections() const
255{
256 std::map<uint16_t, size_t> sectionCounts;
257
258 for (const auto& section : optionalSections())
259 {
260 if (sectionCounts.find(section->header().id) == sectionCounts.end())
261 {
262 sectionCounts[section->header().id] = 1;
263 }
264 else
265 {
266 sectionCounts[section->header().id]++;
267 }
268 }
269
270 std::map<uint16_t, size_t> sections;
271 for (const auto& [id, count] : sectionCounts)
272 {
273 if (count > 1)
274 {
275 // Start with 0 here and printSectionInJSON()
276 // will increment it as it goes.
277 sections.emplace(id, 0);
278 }
279 }
280
281 return sections;
282}
283
Matt Spinler06885452019-11-06 10:35:42 -0600284void PEL::toJSON() const
Aatir186ce8c2019-10-20 15:13:39 -0500285{
Matt Spinleracb7c102020-01-10 13:49:22 -0600286 auto sections = getPluralSections();
287
Aatir186ce8c2019-10-20 15:13:39 -0500288 std::string buf = "{";
Matt Spinleracb7c102020-01-10 13:49:22 -0600289 printSectionInJSON(*(_ph.get()), buf, sections);
290 printSectionInJSON(*(_uh.get()), buf, sections);
Aatir186ce8c2019-10-20 15:13:39 -0500291 for (auto& section : this->optionalSections())
292 {
Matt Spinleracb7c102020-01-10 13:49:22 -0600293 printSectionInJSON(*(section.get()), buf, sections);
Aatir186ce8c2019-10-20 15:13:39 -0500294 }
295 buf += "}";
296 std::size_t found = buf.rfind(",");
297 if (found != std::string::npos)
298 buf.replace(found, 1, "");
299 std::cout << buf << std::endl;
300}
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800301
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600302namespace util
303{
304
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600305std::unique_ptr<UserData> makeJSONUserDataSection(const nlohmann::json& json)
306{
307 auto jsonString = json.dump();
308 std::vector<uint8_t> jsonData(jsonString.begin(), jsonString.end());
309
310 // Pad to a 4 byte boundary
311 while ((jsonData.size() % 4) != 0)
312 {
313 jsonData.push_back(0);
314 }
315
316 return std::make_unique<UserData>(
317 static_cast<uint16_t>(ComponentID::phosphorLogging),
318 static_cast<uint8_t>(UserDataFormat::json),
319 static_cast<uint8_t>(UserDataFormatVersion::json), jsonData);
320}
321
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600322std::unique_ptr<UserData> makeADUserDataSection(const AdditionalData& ad)
323{
324 assert(!ad.empty());
325 nlohmann::json json;
326
327 // Remove the 'ESEL' entry, as it contains a full PEL in the value.
328 if (ad.getValue("ESEL"))
329 {
330 auto newAD = ad;
331 newAD.remove("ESEL");
332 json = newAD.toJSON();
333 }
334 else
335 {
336 json = ad.toJSON();
337 }
338
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600339 return makeJSONUserDataSection(json);
340}
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600341
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600342void addProcessNameToJSON(nlohmann::json& json,
343 const std::optional<std::string>& pid,
344 const DataInterfaceBase& dataIface)
345{
346 std::string name = "Unknown";
347
348 try
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600349 {
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600350 if (pid)
351 {
352 auto n = dataIface.getProcessName(*pid);
353 if (n)
354 {
355 name = *n;
356 }
357 }
358 }
359 catch (std::exception& e)
360 {
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600361 }
362
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600363 json["Process Name"] = std::move(name);
364}
365
366std::unique_ptr<UserData>
367 makeSysInfoUserDataSection(const AdditionalData& ad,
368 const DataInterfaceBase& dataIface)
369{
370 nlohmann::json json;
371
372 addProcessNameToJSON(json, ad.getValue("_PID"), dataIface);
373
374 return makeJSONUserDataSection(json);
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600375}
376
377} // namespace util
378
Matt Spinlercb6b0592019-07-16 15:58:51 -0500379} // namespace pels
380} // namespace openpower