blob: 1add587a3cafb40d44694804dfa3276cb1dcadaa [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 Spinler386a61e2020-08-13 15:51:12 -050019#include "extended_user_data.hpp"
Matt Spinlerc63e2e82019-12-02 15:50:12 -060020#include "extended_user_header.hpp"
Matt Spinleraa659472019-10-23 09:26:48 -050021#include "failing_mtms.hpp"
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +080022#include "json_utils.hpp"
Matt Spinlercb6b0592019-07-16 15:58:51 -050023#include "log_id.hpp"
Matt Spinlerf1e85e22019-11-01 11:31:31 -050024#include "pel_rules.hpp"
Aatir186ce8c2019-10-20 15:13:39 -050025#include "pel_values.hpp"
Matt Spinler131870c2019-09-25 13:29:04 -050026#include "section_factory.hpp"
Matt Spinlerbd716f02019-10-15 10:54:11 -050027#include "src.hpp"
Matt Spinlercb6b0592019-07-16 15:58:51 -050028#include "stream.hpp"
Matt Spinlerafa857c2019-10-24 13:03:46 -050029#include "user_data_formats.hpp"
Matt Spinlercb6b0592019-07-16 15:58:51 -050030
Ben Tynere32b7e72021-05-18 12:38:40 -050031#include <fmt/format.h>
Matt Spinler5b289b22020-03-26 14:27:19 -050032#include <sys/stat.h>
33#include <unistd.h>
34
Aatir186ce8c2019-10-20 15:13:39 -050035#include <iostream>
Matt Spinler07eefc52019-09-26 11:18:26 -050036#include <phosphor-logging/log.hpp>
37
Matt Spinlercb6b0592019-07-16 15:58:51 -050038namespace openpower
39{
40namespace pels
41{
Matt Spinlerb8323632019-09-20 15:11:04 -050042namespace message = openpower::pels::message;
Aatir186ce8c2019-10-20 15:13:39 -050043namespace pv = openpower::pels::pel_values;
Matt Spinler4bfc9082020-03-24 15:05:54 -050044using namespace phosphor::logging;
Matt Spinlerb8323632019-09-20 15:11:04 -050045
Matt Spinler677381b2020-01-23 10:04:29 -060046constexpr auto unknownValue = "Unknown";
Matt Spinler5a90a952020-08-27 09:39:03 -050047constexpr uint8_t jsonCalloutSubtype = 0xCA;
Matt Spinler677381b2020-01-23 10:04:29 -060048
Matt Spinler4bfc9082020-03-24 15:05:54 -050049PEL::PEL(const message::Entry& regEntry, uint32_t obmcLogID, uint64_t timestamp,
Matt Spinlerbd716f02019-10-15 10:54:11 -050050 phosphor::logging::Entry::Level severity,
Matt Spinler56ad2a02020-03-26 14:00:52 -050051 const AdditionalData& additionalData, const PelFFDC& ffdcFiles,
Matt Spinleraa659472019-10-23 09:26:48 -050052 const DataInterfaceBase& dataIface)
Matt Spinlerb8323632019-09-20 15:11:04 -050053{
Matt Spinler85f61a62020-06-03 16:28:55 -050054 std::map<std::string, std::vector<std::string>> debugData;
Matt Spinler5a90a952020-08-27 09:39:03 -050055 nlohmann::json callouts;
Matt Spinler85f61a62020-06-03 16:28:55 -050056
Matt Spinler4bfc9082020-03-24 15:05:54 -050057 _ph = std::make_unique<PrivateHeader>(regEntry.componentID, obmcLogID,
Matt Spinlerb8323632019-09-20 15:11:04 -050058 timestamp);
Vijay Lobo6b3f3452021-04-15 23:04:42 -050059 _uh = std::make_unique<UserHeader>(regEntry, severity, additionalData,
60 dataIface);
Matt Spinlerb8323632019-09-20 15:11:04 -050061
Matt Spinler5a90a952020-08-27 09:39:03 -050062 // Extract any callouts embedded in an FFDC file.
63 if (!ffdcFiles.empty())
64 {
65 try
66 {
67 callouts = getCalloutJSON(ffdcFiles);
68 }
69 catch (const std::exception& e)
70 {
71 debugData.emplace("FFDC file JSON callouts error",
72 std::vector<std::string>{e.what()});
73 }
74 }
75
76 auto src =
77 std::make_unique<SRC>(regEntry, additionalData, callouts, dataIface);
78
Matt Spinler85f61a62020-06-03 16:28:55 -050079 if (!src->getDebugData().empty())
80 {
81 // Something didn't go as planned
82 debugData.emplace("SRC", src->getDebugData());
83 }
Matt Spinlerc63e2e82019-12-02 15:50:12 -060084
Matt Spinler4bfc9082020-03-24 15:05:54 -050085 auto euh = std::make_unique<ExtendedUserHeader>(dataIface, regEntry, *src);
Matt Spinlerc63e2e82019-12-02 15:50:12 -060086
Matt Spinlerbd716f02019-10-15 10:54:11 -050087 _optionalSections.push_back(std::move(src));
Matt Spinlerc63e2e82019-12-02 15:50:12 -060088 _optionalSections.push_back(std::move(euh));
Matt Spinlerb8323632019-09-20 15:11:04 -050089
Matt Spinleraa659472019-10-23 09:26:48 -050090 auto mtms = std::make_unique<FailingMTMS>(dataIface);
91 _optionalSections.push_back(std::move(mtms));
Matt Spinlerbd716f02019-10-15 10:54:11 -050092
Matt Spinler4dcd3f42020-01-22 14:55:07 -060093 auto ud = util::makeSysInfoUserDataSection(additionalData, dataIface);
Matt Spinler85f61a62020-06-03 16:28:55 -050094 addUserDataSection(std::move(ud));
Matt Spinler4dcd3f42020-01-22 14:55:07 -060095
Matt Spinler9b7e94f2020-03-24 15:44:41 -050096 // Create a UserData section from AdditionalData.
Matt Spinlerafa857c2019-10-24 13:03:46 -050097 if (!additionalData.empty())
98 {
Matt Spinler4dcd3f42020-01-22 14:55:07 -060099 ud = util::makeADUserDataSection(additionalData);
Matt Spinler85f61a62020-06-03 16:28:55 -0500100 addUserDataSection(std::move(ud));
Matt Spinlerafa857c2019-10-24 13:03:46 -0500101 }
102
Matt Spinler56ad2a02020-03-26 14:00:52 -0500103 // Add any FFDC files into UserData sections
104 for (const auto& file : ffdcFiles)
105 {
106 ud = util::makeFFDCuserDataSection(regEntry.componentID, file);
107 if (!ud)
108 {
Matt Spinler85f61a62020-06-03 16:28:55 -0500109 // Add this error into the debug data UserData section
110 std::ostringstream msg;
111 msg << "Could not make PEL FFDC UserData section from file"
112 << std::hex << regEntry.componentID << " " << file.subType
113 << " " << file.version;
114 if (debugData.count("FFDC File"))
115 {
116 debugData.at("FFDC File").push_back(msg.str());
117 }
118 else
119 {
120 debugData.emplace("FFDC File",
121 std::vector<std::string>{msg.str()});
122 }
123
Matt Spinler56ad2a02020-03-26 14:00:52 -0500124 continue;
125 }
126
Matt Spinler85f61a62020-06-03 16:28:55 -0500127 addUserDataSection(std::move(ud));
128 }
Matt Spinler56ad2a02020-03-26 14:00:52 -0500129
Matt Spinler85f61a62020-06-03 16:28:55 -0500130 // Store in the PEL any important debug data created while
131 // building the PEL sections.
132 if (!debugData.empty())
133 {
134 nlohmann::json data;
135 data["PEL Internal Debug Data"] = debugData;
136 ud = util::makeJSONUserDataSection(data);
137
138 addUserDataSection(std::move(ud));
139
140 // Also put in the journal for debug
141 for (const auto& [name, data] : debugData)
142 {
143 for (const auto& message : data)
144 {
145 std::string entry = name + ": " + message;
146 log<level::INFO>(entry.c_str());
Matt Spinler56ad2a02020-03-26 14:00:52 -0500147 }
148 }
Matt Spinler56ad2a02020-03-26 14:00:52 -0500149 }
150
Matt Spinler97d19b42019-10-29 11:34:03 -0500151 _ph->setSectionCount(2 + _optionalSections.size());
Matt Spinlerf1e85e22019-11-01 11:31:31 -0500152
153 checkRulesAndFix();
Matt Spinlerb8323632019-09-20 15:11:04 -0500154}
Matt Spinlercb6b0592019-07-16 15:58:51 -0500155
Matt Spinler07eefc52019-09-26 11:18:26 -0500156PEL::PEL(std::vector<uint8_t>& data) : PEL(data, 0)
Matt Spinlercb6b0592019-07-16 15:58:51 -0500157{
158}
159
Matt Spinler07eefc52019-09-26 11:18:26 -0500160PEL::PEL(std::vector<uint8_t>& data, uint32_t obmcLogID)
Matt Spinlercb6b0592019-07-16 15:58:51 -0500161{
Matt Spinler07eefc52019-09-26 11:18:26 -0500162 populateFromRawData(data, obmcLogID);
Matt Spinlercb6b0592019-07-16 15:58:51 -0500163}
164
Matt Spinler07eefc52019-09-26 11:18:26 -0500165void PEL::populateFromRawData(std::vector<uint8_t>& data, uint32_t obmcLogID)
Matt Spinlercb6b0592019-07-16 15:58:51 -0500166{
Matt Spinler07eefc52019-09-26 11:18:26 -0500167 Stream pelData{data};
Matt Spinlercb6b0592019-07-16 15:58:51 -0500168 _ph = std::make_unique<PrivateHeader>(pelData);
169 if (obmcLogID != 0)
170 {
Matt Spinler97d19b42019-10-29 11:34:03 -0500171 _ph->setOBMCLogID(obmcLogID);
Matt Spinlercb6b0592019-07-16 15:58:51 -0500172 }
173
174 _uh = std::make_unique<UserHeader>(pelData);
Matt Spinler131870c2019-09-25 13:29:04 -0500175
176 // Use the section factory to create the rest of the objects
177 for (size_t i = 2; i < _ph->sectionCount(); i++)
178 {
179 auto section = section_factory::create(pelData);
180 _optionalSections.push_back(std::move(section));
181 }
Matt Spinlercb6b0592019-07-16 15:58:51 -0500182}
183
184bool PEL::valid() const
185{
186 bool valid = _ph->valid();
187
188 if (valid)
189 {
190 valid = _uh->valid();
191 }
192
Matt Spinler131870c2019-09-25 13:29:04 -0500193 if (valid)
194 {
195 if (!std::all_of(_optionalSections.begin(), _optionalSections.end(),
196 [](const auto& section) { return section->valid(); }))
197 {
198 valid = false;
199 }
200 }
201
Matt Spinlercb6b0592019-07-16 15:58:51 -0500202 return valid;
203}
204
205void PEL::setCommitTime()
206{
207 auto now = std::chrono::system_clock::now();
Matt Spinler97d19b42019-10-29 11:34:03 -0500208 _ph->setCommitTimestamp(getBCDTime(now));
Matt Spinlercb6b0592019-07-16 15:58:51 -0500209}
210
211void PEL::assignID()
212{
Matt Spinler97d19b42019-10-29 11:34:03 -0500213 _ph->setID(generatePELID());
Matt Spinlercb6b0592019-07-16 15:58:51 -0500214}
215
Matt Spinler06885452019-11-06 10:35:42 -0600216void PEL::flatten(std::vector<uint8_t>& pelBuffer) const
Matt Spinlercb6b0592019-07-16 15:58:51 -0500217{
218 Stream pelData{pelBuffer};
Matt Spinlerb8323632019-09-20 15:11:04 -0500219
Matt Spinler07eefc52019-09-26 11:18:26 -0500220 if (!valid())
Matt Spinlercb6b0592019-07-16 15:58:51 -0500221 {
Matt Spinler07eefc52019-09-26 11:18:26 -0500222 log<level::WARNING>("Unflattening an invalid PEL");
Matt Spinlercb6b0592019-07-16 15:58:51 -0500223 }
224
Matt Spinler07eefc52019-09-26 11:18:26 -0500225 _ph->flatten(pelData);
Matt Spinlerb8323632019-09-20 15:11:04 -0500226 _uh->flatten(pelData);
Matt Spinler07eefc52019-09-26 11:18:26 -0500227
228 for (auto& section : _optionalSections)
229 {
230 section->flatten(pelData);
231 }
Matt Spinlercb6b0592019-07-16 15:58:51 -0500232}
233
Matt Spinler06885452019-11-06 10:35:42 -0600234std::vector<uint8_t> PEL::data() const
Matt Spinlercb6b0592019-07-16 15:58:51 -0500235{
Matt Spinler07eefc52019-09-26 11:18:26 -0500236 std::vector<uint8_t> pelData;
237 flatten(pelData);
238 return pelData;
Matt Spinlercb6b0592019-07-16 15:58:51 -0500239}
240
Matt Spinlerf1b46ff2020-01-22 14:10:04 -0600241size_t PEL::size() const
242{
243 size_t size = 0;
244
245 if (_ph)
246 {
247 size += _ph->header().size;
248 }
249
250 if (_uh)
251 {
252 size += _uh->header().size;
253 }
254
255 for (const auto& section : _optionalSections)
256 {
257 size += section->header().size;
258 }
259
260 return size;
261}
262
Matt Spinlerbd716f02019-10-15 10:54:11 -0500263std::optional<SRC*> PEL::primarySRC() const
264{
265 auto src = std::find_if(
266 _optionalSections.begin(), _optionalSections.end(), [](auto& section) {
267 return section->header().id ==
268 static_cast<uint16_t>(SectionID::primarySRC);
269 });
270 if (src != _optionalSections.end())
271 {
272 return static_cast<SRC*>(src->get());
273 }
274
275 return std::nullopt;
276}
277
Matt Spinlerf1e85e22019-11-01 11:31:31 -0500278void PEL::checkRulesAndFix()
279{
Matt Spinler1f93c592020-09-10 10:43:08 -0500280 // Only fix if the action flags are at their default value which
281 // means they weren't specified in the registry. Otherwise
282 // assume the user knows what they are doing.
283 if (_uh->actionFlags() == actionFlagsDefault)
284 {
285 auto [actionFlags, eventType] =
286 pel_rules::check(0, _uh->eventType(), _uh->severity());
Matt Spinlerf1e85e22019-11-01 11:31:31 -0500287
Matt Spinler1f93c592020-09-10 10:43:08 -0500288 _uh->setActionFlags(actionFlags);
289 _uh->setEventType(eventType);
290 }
Matt Spinlerf1e85e22019-11-01 11:31:31 -0500291}
292
Matt Spinleracb7c102020-01-10 13:49:22 -0600293void PEL::printSectionInJSON(const Section& section, std::string& buf,
Harisuddin Mohamed Isaa214ed32020-02-28 15:58:23 +0800294 std::map<uint16_t, size_t>& pluralSections,
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800295 message::Registry& registry,
296 const std::vector<std::string>& plugins,
297 uint8_t creatorID) const
Aatir186ce8c2019-10-20 15:13:39 -0500298{
299 char tmpB[5];
Aatir Manzurad0e0472019-10-07 13:18:37 -0500300 uint8_t id[] = {static_cast<uint8_t>(section.header().id >> 8),
301 static_cast<uint8_t>(section.header().id)};
302 sprintf(tmpB, "%c%c", id[0], id[1]);
303 std::string sectionID(tmpB);
304 std::string sectionName = pv::sectionTitles.count(sectionID)
305 ? pv::sectionTitles.at(sectionID)
306 : "Unknown Section";
Matt Spinleracb7c102020-01-10 13:49:22 -0600307
308 // Add a count if there are multiple of this type of section
309 auto count = pluralSections.find(section.header().id);
310 if (count != pluralSections.end())
311 {
312 sectionName += " " + std::to_string(count->second);
313 count->second++;
314 }
315
Aatir186ce8c2019-10-20 15:13:39 -0500316 if (section.valid())
317 {
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800318 std::optional<std::string> json;
319 if (sectionID == "PS" || sectionID == "SS")
320 {
Harisuddin Mohamed Isac8d6cc62020-08-19 22:47:19 +0800321 json = section.getJSON(registry, plugins, creatorID);
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800322 }
Matt Spinler386a61e2020-08-13 15:51:12 -0500323 else if ((sectionID == "UD") || (sectionID == "ED"))
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800324 {
Harisuddin Mohamed Isa3fdcd4e2020-08-26 11:56:42 +0800325 json = section.getJSON(creatorID, plugins);
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800326 }
327 else
328 {
329 json = section.getJSON();
330 }
Matt Spinler4220a152020-03-26 10:18:09 -0500331
332 buf += "\"" + sectionName + "\": {\n";
333
Aatir Manzurad0e0472019-10-07 13:18:37 -0500334 if (json)
335 {
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800336 buf += *json + "\n},\n";
Aatir Manzurad0e0472019-10-07 13:18:37 -0500337 }
338 else
339 {
Matt Spinler4220a152020-03-26 10:18:09 -0500340 jsonInsert(buf, pv::sectionVer,
341 getNumberString("%d", section.header().version), 1);
342 jsonInsert(buf, pv::subSection,
343 getNumberString("%d", section.header().subType), 1);
344 jsonInsert(buf, pv::createdBy,
345 getNumberString("0x%X", section.header().componentID),
346 1);
347
Aatir Manzurad0e0472019-10-07 13:18:37 -0500348 std::vector<uint8_t> data;
349 Stream s{data};
350 section.flatten(s);
Matt Spinler4220a152020-03-26 10:18:09 -0500351 std::string dstr =
352 dumpHex(std::data(data) + SectionHeader::flattenedSize(),
Harisuddin Mohamed Isa097ad122020-06-11 21:19:41 +0800353 data.size() - SectionHeader::flattenedSize(), 2);
Matt Spinler4220a152020-03-26 10:18:09 -0500354 std::string jsonIndent(indentLevel, 0x20);
355 buf += jsonIndent + "\"Data\": [\n";
356 buf += dstr;
357 buf += jsonIndent + "]\n";
358 buf += "},\n";
Aatir Manzurad0e0472019-10-07 13:18:37 -0500359 }
Aatir186ce8c2019-10-20 15:13:39 -0500360 }
361 else
362 {
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800363 buf += "\n\"Invalid Section\": [\n \"invalid\"\n],\n";
Aatir186ce8c2019-10-20 15:13:39 -0500364 }
365}
366
Matt Spinleracb7c102020-01-10 13:49:22 -0600367std::map<uint16_t, size_t> PEL::getPluralSections() const
368{
369 std::map<uint16_t, size_t> sectionCounts;
370
371 for (const auto& section : optionalSections())
372 {
373 if (sectionCounts.find(section->header().id) == sectionCounts.end())
374 {
375 sectionCounts[section->header().id] = 1;
376 }
377 else
378 {
379 sectionCounts[section->header().id]++;
380 }
381 }
382
383 std::map<uint16_t, size_t> sections;
384 for (const auto& [id, count] : sectionCounts)
385 {
386 if (count > 1)
387 {
388 // Start with 0 here and printSectionInJSON()
389 // will increment it as it goes.
390 sections.emplace(id, 0);
391 }
392 }
393
394 return sections;
395}
396
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800397void PEL::toJSON(message::Registry& registry,
398 const std::vector<std::string>& plugins) const
Aatir186ce8c2019-10-20 15:13:39 -0500399{
Matt Spinleracb7c102020-01-10 13:49:22 -0600400 auto sections = getPluralSections();
401
Harisuddin Mohamed Isaa214ed32020-02-28 15:58:23 +0800402 std::string buf = "{\n";
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800403 printSectionInJSON(*(_ph.get()), buf, sections, registry, plugins);
404 printSectionInJSON(*(_uh.get()), buf, sections, registry, plugins);
Aatir186ce8c2019-10-20 15:13:39 -0500405 for (auto& section : this->optionalSections())
406 {
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800407 printSectionInJSON(*(section.get()), buf, sections, registry, plugins,
408 _ph->creatorID());
Aatir186ce8c2019-10-20 15:13:39 -0500409 }
410 buf += "}";
411 std::size_t found = buf.rfind(",");
412 if (found != std::string::npos)
413 buf.replace(found, 1, "");
414 std::cout << buf << std::endl;
415}
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800416
Matt Spinler85f61a62020-06-03 16:28:55 -0500417bool PEL::addUserDataSection(std::unique_ptr<UserData> userData)
418{
419 if (size() + userData->header().size > _maxPELSize)
420 {
421 if (userData->shrink(_maxPELSize - size()))
422 {
423 _optionalSections.push_back(std::move(userData));
424 }
425 else
426 {
427 log<level::WARNING>(
428 "Could not shrink UserData section. Dropping",
429 entry("SECTION_SIZE=%d\n", userData->header().size),
430 entry("COMPONENT_ID=0x%02X", userData->header().componentID),
431 entry("SUBTYPE=0x%X", userData->header().subType),
432 entry("VERSION=0x%X", userData->header().version));
433 return false;
434 }
435 }
436 else
437 {
438 _optionalSections.push_back(std::move(userData));
439 }
440 return true;
441}
442
Matt Spinler5a90a952020-08-27 09:39:03 -0500443nlohmann::json PEL::getCalloutJSON(const PelFFDC& ffdcFiles)
444{
445 nlohmann::json callouts;
446
447 for (const auto& file : ffdcFiles)
448 {
449 if ((file.format == UserDataFormat::json) &&
450 (file.subType == jsonCalloutSubtype))
451 {
452 auto data = util::readFD(file.fd);
453 if (data.empty())
454 {
455 throw std::runtime_error{
456 "Could not get data from JSON callout file descriptor"};
457 }
458
459 std::string jsonString{data.begin(), data.begin() + data.size()};
460
461 callouts = nlohmann::json::parse(jsonString);
462 break;
463 }
464 }
465
466 return callouts;
467}
468
Andrew Geissler44fc3162020-07-09 09:21:31 -0500469bool PEL::isCalloutPresent() const
470{
471 auto pSRC = primarySRC();
472 if (!pSRC)
473 {
474 return false;
475 }
476
477 bool calloutPresent = false;
478 if ((*pSRC)->callouts())
479 {
480 for (auto& i : (*pSRC)->callouts()->callouts())
481 {
482 if (((*i).fruIdentity()))
483 {
484 auto& fruId = (*i).fruIdentity();
485 if ((*fruId).failingComponentType() != 0)
486 {
487 calloutPresent = true;
488 break;
489 }
490 }
491 }
492 }
493
494 return calloutPresent;
495}
496
Sumit Kumar3160a542021-04-26 08:07:04 -0500497void PEL::updateSysInfoInExtendedUserDataSection(
498 const DataInterfaceBase& dataIface)
499{
500 const AdditionalData additionalData;
501
502 // Check for PEL from Hostboot
503 if (_ph->creatorID() == static_cast<uint8_t>(CreatorID::hostboot))
504 {
505 // Get the ED section from PEL
506 auto op = std::find_if(_optionalSections.begin(),
507 _optionalSections.end(), [](auto& section) {
508 return section->header().id ==
509 static_cast<uint16_t>(
510 SectionID::extUserData);
511 });
512
513 // Check for ED section found and its not the last section of PEL
514 if (op != _optionalSections.end())
515 {
516 // Get the extended user data class mapped to found section
517 auto extUserData = static_cast<ExtendedUserData*>(op->get());
518
519 // Check for the creator ID is for OpenBMC
520 if (extUserData->creatorID() ==
521 static_cast<uint8_t>(CreatorID::openBMC))
522 {
523 // Update subtype and component id
524 auto subType = static_cast<uint8_t>(UserDataFormat::json);
525 auto componentId =
526 static_cast<uint16_t>(ComponentID::phosphorLogging);
527
528 // Update system data to ED section
529 auto ud =
530 util::makeSysInfoUserDataSection(additionalData, dataIface);
531 extUserData->updateDataSection(subType, componentId,
532 ud->data());
533 }
534 }
535 }
536}
537
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600538namespace util
539{
540
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600541std::unique_ptr<UserData> makeJSONUserDataSection(const nlohmann::json& json)
542{
543 auto jsonString = json.dump();
544 std::vector<uint8_t> jsonData(jsonString.begin(), jsonString.end());
545
546 // Pad to a 4 byte boundary
547 while ((jsonData.size() % 4) != 0)
548 {
549 jsonData.push_back(0);
550 }
551
552 return std::make_unique<UserData>(
553 static_cast<uint16_t>(ComponentID::phosphorLogging),
554 static_cast<uint8_t>(UserDataFormat::json),
555 static_cast<uint8_t>(UserDataFormatVersion::json), jsonData);
556}
557
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600558std::unique_ptr<UserData> makeADUserDataSection(const AdditionalData& ad)
559{
560 assert(!ad.empty());
561 nlohmann::json json;
562
563 // Remove the 'ESEL' entry, as it contains a full PEL in the value.
564 if (ad.getValue("ESEL"))
565 {
566 auto newAD = ad;
567 newAD.remove("ESEL");
568 json = newAD.toJSON();
569 }
570 else
571 {
572 json = ad.toJSON();
573 }
574
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600575 return makeJSONUserDataSection(json);
576}
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600577
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600578void addProcessNameToJSON(nlohmann::json& json,
579 const std::optional<std::string>& pid,
580 const DataInterfaceBase& dataIface)
581{
Matt Spinler677381b2020-01-23 10:04:29 -0600582 std::string name{unknownValue};
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600583
584 try
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600585 {
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600586 if (pid)
587 {
588 auto n = dataIface.getProcessName(*pid);
589 if (n)
590 {
591 name = *n;
592 }
593 }
594 }
595 catch (std::exception& e)
596 {
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600597 }
598
Sumit Kumar3160a542021-04-26 08:07:04 -0500599 if (pid)
600 {
601 json["Process Name"] = std::move(name);
602 }
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600603}
604
Matt Spinler677381b2020-01-23 10:04:29 -0600605void addBMCFWVersionIDToJSON(nlohmann::json& json,
606 const DataInterfaceBase& dataIface)
607{
608 auto id = dataIface.getBMCFWVersionID();
609 if (id.empty())
610 {
611 id = unknownValue;
612 }
613
Matt Spinlerc2b8a512021-05-21 12:44:42 -0600614 json["FW Version ID"] = std::move(id);
Matt Spinler677381b2020-01-23 10:04:29 -0600615}
616
Matt Spinler4aa23a12020-02-03 15:05:09 -0600617std::string lastSegment(char separator, std::string data)
618{
619 auto pos = data.find_last_of(separator);
620 if (pos != std::string::npos)
621 {
622 data = data.substr(pos + 1);
623 }
624
625 return data;
626}
627
Ben Tynere32b7e72021-05-18 12:38:40 -0500628void addIMKeyword(nlohmann::json& json, const DataInterfaceBase& dataIface)
629{
630 auto keyword = dataIface.getSystemIMKeyword();
631
632 std::string value{};
633
634 std::for_each(keyword.begin(), keyword.end(), [&](const auto& byte) {
635 value += fmt::format("{:02X}", byte);
636 });
637
638 json["System IM"] = value;
639}
640
Matt Spinler4aa23a12020-02-03 15:05:09 -0600641void addStatesToJSON(nlohmann::json& json, const DataInterfaceBase& dataIface)
642{
643 json["BMCState"] = lastSegment('.', dataIface.getBMCState());
644 json["ChassisState"] = lastSegment('.', dataIface.getChassisState());
645 json["HostState"] = lastSegment('.', dataIface.getHostState());
646}
647
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600648std::unique_ptr<UserData>
649 makeSysInfoUserDataSection(const AdditionalData& ad,
650 const DataInterfaceBase& dataIface)
651{
652 nlohmann::json json;
653
654 addProcessNameToJSON(json, ad.getValue("_PID"), dataIface);
Matt Spinler677381b2020-01-23 10:04:29 -0600655 addBMCFWVersionIDToJSON(json, dataIface);
Ben Tynere32b7e72021-05-18 12:38:40 -0500656 addIMKeyword(json, dataIface);
Matt Spinler4aa23a12020-02-03 15:05:09 -0600657 addStatesToJSON(json, dataIface);
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600658
659 return makeJSONUserDataSection(json);
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600660}
661
Matt Spinler5b289b22020-03-26 14:27:19 -0500662std::vector<uint8_t> readFD(int fd)
663{
664 std::vector<uint8_t> data;
665
666 // Get the size
667 struct stat s;
668 int r = fstat(fd, &s);
669 if (r != 0)
670 {
671 auto e = errno;
672 log<level::ERR>("Could not get FFDC file size from FD",
673 entry("ERRNO=%d", e));
674 return data;
675 }
676
677 if (0 == s.st_size)
678 {
679 log<level::ERR>("FFDC file is empty");
680 return data;
681 }
682
683 data.resize(s.st_size);
684
685 // Make sure its at the beginning, as maybe another
686 // extension already used it.
687 r = lseek(fd, 0, SEEK_SET);
688 if (r == -1)
689 {
690 auto e = errno;
691 log<level::ERR>("Could not seek to beginning of FFDC file",
692 entry("ERRNO=%d", e));
693 return data;
694 }
695
696 r = read(fd, data.data(), s.st_size);
697 if (r == -1)
698 {
699 auto e = errno;
700 log<level::ERR>("Could not read FFDC file", entry("ERRNO=%d", e));
701 }
702 else if (r != s.st_size)
703 {
704 log<level::WARNING>("Could not read full FFDC file",
705 entry("FILE_SIZE=%d", s.st_size),
706 entry("SIZE_READ=%d", r));
707 }
708
709 return data;
710}
711
Matt Spinler56ad2a02020-03-26 14:00:52 -0500712std::unique_ptr<UserData> makeFFDCuserDataSection(uint16_t componentID,
713 const PelFFDCfile& file)
714{
Matt Spinler5b289b22020-03-26 14:27:19 -0500715 auto data = readFD(file.fd);
716
717 if (data.empty())
718 {
719 return std::unique_ptr<UserData>();
720 }
721
722 // The data needs 4 Byte alignment, and save amount padded for the
723 // CBOR case.
724 uint32_t pad = 0;
725 while (data.size() % 4)
726 {
727 data.push_back(0);
728 pad++;
729 }
730
731 // For JSON, CBOR, and Text use our component ID, subType, and version,
732 // otherwise use the supplied ones.
733 uint16_t compID = static_cast<uint16_t>(ComponentID::phosphorLogging);
734 uint8_t subType{};
735 uint8_t version{};
736
737 switch (file.format)
738 {
739 case UserDataFormat::json:
740 subType = static_cast<uint8_t>(UserDataFormat::json);
741 version = static_cast<uint8_t>(UserDataFormatVersion::json);
742 break;
743 case UserDataFormat::cbor:
744 subType = static_cast<uint8_t>(UserDataFormat::cbor);
745 version = static_cast<uint8_t>(UserDataFormatVersion::cbor);
746
747 // The CBOR parser will fail on the extra pad bytes since they
748 // aren't CBOR. Add the amount we padded to the end and other
749 // code will remove it all before parsing.
750 {
751 data.resize(data.size() + 4);
752 Stream stream{data};
753 stream.offset(data.size() - 4);
754 stream << pad;
755 }
756
757 break;
758 case UserDataFormat::text:
759 subType = static_cast<uint8_t>(UserDataFormat::text);
760 version = static_cast<uint8_t>(UserDataFormatVersion::text);
761 break;
762 case UserDataFormat::custom:
763 default:
764 // Use the passed in values
765 compID = componentID;
766 subType = file.subType;
767 version = file.version;
768 break;
769 }
770
771 return std::make_unique<UserData>(compID, subType, version, data);
Matt Spinler56ad2a02020-03-26 14:00:52 -0500772}
773
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600774} // namespace util
775
Matt Spinlercb6b0592019-07-16 15:58:51 -0500776} // namespace pels
777} // namespace openpower