blob: c741727154f6cb1143adab9d95810f0a74458d6e [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
Matt Spinler5b289b22020-03-26 14:27:19 -050030#include <sys/stat.h>
31#include <unistd.h>
32
Aatir186ce8c2019-10-20 15:13:39 -050033#include <iostream>
Matt Spinler07eefc52019-09-26 11:18:26 -050034#include <phosphor-logging/log.hpp>
35
Matt Spinlercb6b0592019-07-16 15:58:51 -050036namespace openpower
37{
38namespace pels
39{
Matt Spinlerb8323632019-09-20 15:11:04 -050040namespace message = openpower::pels::message;
Aatir186ce8c2019-10-20 15:13:39 -050041namespace pv = openpower::pels::pel_values;
Matt Spinler4bfc9082020-03-24 15:05:54 -050042using namespace phosphor::logging;
Matt Spinlerb8323632019-09-20 15:11:04 -050043
Matt Spinler677381b2020-01-23 10:04:29 -060044constexpr auto unknownValue = "Unknown";
45
Matt Spinler4bfc9082020-03-24 15:05:54 -050046PEL::PEL(const message::Entry& regEntry, uint32_t obmcLogID, uint64_t timestamp,
Matt Spinlerbd716f02019-10-15 10:54:11 -050047 phosphor::logging::Entry::Level severity,
Matt Spinler56ad2a02020-03-26 14:00:52 -050048 const AdditionalData& additionalData, const PelFFDC& ffdcFiles,
Matt Spinleraa659472019-10-23 09:26:48 -050049 const DataInterfaceBase& dataIface)
Matt Spinlerb8323632019-09-20 15:11:04 -050050{
Matt Spinler4bfc9082020-03-24 15:05:54 -050051 _ph = std::make_unique<PrivateHeader>(regEntry.componentID, obmcLogID,
Matt Spinlerb8323632019-09-20 15:11:04 -050052 timestamp);
Matt Spinler4bfc9082020-03-24 15:05:54 -050053 _uh = std::make_unique<UserHeader>(regEntry, severity);
Matt Spinlerb8323632019-09-20 15:11:04 -050054
Matt Spinler4bfc9082020-03-24 15:05:54 -050055 auto src = std::make_unique<SRC>(regEntry, additionalData, dataIface);
Matt Spinlerc63e2e82019-12-02 15:50:12 -060056
Matt Spinler4bfc9082020-03-24 15:05:54 -050057 auto euh = std::make_unique<ExtendedUserHeader>(dataIface, regEntry, *src);
Matt Spinlerc63e2e82019-12-02 15:50:12 -060058
Matt Spinlerbd716f02019-10-15 10:54:11 -050059 _optionalSections.push_back(std::move(src));
Matt Spinlerc63e2e82019-12-02 15:50:12 -060060 _optionalSections.push_back(std::move(euh));
Matt Spinlerb8323632019-09-20 15:11:04 -050061
Matt Spinleraa659472019-10-23 09:26:48 -050062 auto mtms = std::make_unique<FailingMTMS>(dataIface);
63 _optionalSections.push_back(std::move(mtms));
Matt Spinlerbd716f02019-10-15 10:54:11 -050064
Matt Spinler4dcd3f42020-01-22 14:55:07 -060065 auto ud = util::makeSysInfoUserDataSection(additionalData, dataIface);
66 _optionalSections.push_back(std::move(ud));
67
Matt Spinler9b7e94f2020-03-24 15:44:41 -050068 // Create a UserData section from AdditionalData.
Matt Spinlerafa857c2019-10-24 13:03:46 -050069 if (!additionalData.empty())
70 {
Matt Spinler4dcd3f42020-01-22 14:55:07 -060071 ud = util::makeADUserDataSection(additionalData);
Matt Spinler6d663822020-01-22 14:50:46 -060072
Matt Spinler9b7e94f2020-03-24 15:44:41 -050073 // Shrink the section if necessary.
74 if (size() + ud->header().size > _maxPELSize)
75 {
76 if (ud->shrink(_maxPELSize - size()))
77 {
78 _optionalSections.push_back(std::move(ud));
79 }
80 else
81 {
82 log<level::WARNING>(
83 "Dropping AdditionalData UserData section",
84 entry("SECTION_SIZE=%d\n", ud->header().size));
85 }
86 }
87 else
Matt Spinler6d663822020-01-22 14:50:46 -060088 {
89 _optionalSections.push_back(std::move(ud));
90 }
Matt Spinlerafa857c2019-10-24 13:03:46 -050091 }
92
Matt Spinler56ad2a02020-03-26 14:00:52 -050093 // Add any FFDC files into UserData sections
94 for (const auto& file : ffdcFiles)
95 {
96 ud = util::makeFFDCuserDataSection(regEntry.componentID, file);
97 if (!ud)
98 {
99 log<level::WARNING>(
100 "Could not make PEL FFDC UserData section from file",
101 entry("COMPONENT_ID=0x%02X", regEntry.componentID),
102 entry("SUBTYPE=0x%X", file.subType),
103 entry("VERSION=0x%X", file.version));
104 continue;
105 }
106
107 // Shrink it if necessary
108 if (size() + ud->header().size > _maxPELSize)
109 {
110 if (!ud->shrink(_maxPELSize - size()))
111 {
112 log<level::WARNING>(
113 "Could not shrink FFDC UserData section",
114 entry("COMPONENT_ID=0x%02X", regEntry.componentID),
115 entry("SUBTYPE=0x%X", file.subType),
116 entry("VERSION=0x%X", file.version));
117
118 // Give up adding FFDC
119 break;
120 }
121 }
122
123 _optionalSections.push_back(std::move(ud));
124 }
125
Matt Spinler97d19b42019-10-29 11:34:03 -0500126 _ph->setSectionCount(2 + _optionalSections.size());
Matt Spinlerf1e85e22019-11-01 11:31:31 -0500127
128 checkRulesAndFix();
Matt Spinlerb8323632019-09-20 15:11:04 -0500129}
Matt Spinlercb6b0592019-07-16 15:58:51 -0500130
Matt Spinler07eefc52019-09-26 11:18:26 -0500131PEL::PEL(std::vector<uint8_t>& data) : PEL(data, 0)
Matt Spinlercb6b0592019-07-16 15:58:51 -0500132{
133}
134
Matt Spinler07eefc52019-09-26 11:18:26 -0500135PEL::PEL(std::vector<uint8_t>& data, uint32_t obmcLogID)
Matt Spinlercb6b0592019-07-16 15:58:51 -0500136{
Matt Spinler07eefc52019-09-26 11:18:26 -0500137 populateFromRawData(data, obmcLogID);
Matt Spinlercb6b0592019-07-16 15:58:51 -0500138}
139
Matt Spinler07eefc52019-09-26 11:18:26 -0500140void PEL::populateFromRawData(std::vector<uint8_t>& data, uint32_t obmcLogID)
Matt Spinlercb6b0592019-07-16 15:58:51 -0500141{
Matt Spinler07eefc52019-09-26 11:18:26 -0500142 Stream pelData{data};
Matt Spinlercb6b0592019-07-16 15:58:51 -0500143 _ph = std::make_unique<PrivateHeader>(pelData);
144 if (obmcLogID != 0)
145 {
Matt Spinler97d19b42019-10-29 11:34:03 -0500146 _ph->setOBMCLogID(obmcLogID);
Matt Spinlercb6b0592019-07-16 15:58:51 -0500147 }
148
149 _uh = std::make_unique<UserHeader>(pelData);
Matt Spinler131870c2019-09-25 13:29:04 -0500150
151 // Use the section factory to create the rest of the objects
152 for (size_t i = 2; i < _ph->sectionCount(); i++)
153 {
154 auto section = section_factory::create(pelData);
155 _optionalSections.push_back(std::move(section));
156 }
Matt Spinlercb6b0592019-07-16 15:58:51 -0500157}
158
159bool PEL::valid() const
160{
161 bool valid = _ph->valid();
162
163 if (valid)
164 {
165 valid = _uh->valid();
166 }
167
Matt Spinler131870c2019-09-25 13:29:04 -0500168 if (valid)
169 {
170 if (!std::all_of(_optionalSections.begin(), _optionalSections.end(),
171 [](const auto& section) { return section->valid(); }))
172 {
173 valid = false;
174 }
175 }
176
Matt Spinlercb6b0592019-07-16 15:58:51 -0500177 return valid;
178}
179
180void PEL::setCommitTime()
181{
182 auto now = std::chrono::system_clock::now();
Matt Spinler97d19b42019-10-29 11:34:03 -0500183 _ph->setCommitTimestamp(getBCDTime(now));
Matt Spinlercb6b0592019-07-16 15:58:51 -0500184}
185
186void PEL::assignID()
187{
Matt Spinler97d19b42019-10-29 11:34:03 -0500188 _ph->setID(generatePELID());
Matt Spinlercb6b0592019-07-16 15:58:51 -0500189}
190
Matt Spinler06885452019-11-06 10:35:42 -0600191void PEL::flatten(std::vector<uint8_t>& pelBuffer) const
Matt Spinlercb6b0592019-07-16 15:58:51 -0500192{
193 Stream pelData{pelBuffer};
Matt Spinlerb8323632019-09-20 15:11:04 -0500194
Matt Spinler07eefc52019-09-26 11:18:26 -0500195 if (!valid())
Matt Spinlercb6b0592019-07-16 15:58:51 -0500196 {
Matt Spinler07eefc52019-09-26 11:18:26 -0500197 log<level::WARNING>("Unflattening an invalid PEL");
Matt Spinlercb6b0592019-07-16 15:58:51 -0500198 }
199
Matt Spinler07eefc52019-09-26 11:18:26 -0500200 _ph->flatten(pelData);
Matt Spinlerb8323632019-09-20 15:11:04 -0500201 _uh->flatten(pelData);
Matt Spinler07eefc52019-09-26 11:18:26 -0500202
203 for (auto& section : _optionalSections)
204 {
205 section->flatten(pelData);
206 }
Matt Spinlercb6b0592019-07-16 15:58:51 -0500207}
208
Matt Spinler06885452019-11-06 10:35:42 -0600209std::vector<uint8_t> PEL::data() const
Matt Spinlercb6b0592019-07-16 15:58:51 -0500210{
Matt Spinler07eefc52019-09-26 11:18:26 -0500211 std::vector<uint8_t> pelData;
212 flatten(pelData);
213 return pelData;
Matt Spinlercb6b0592019-07-16 15:58:51 -0500214}
215
Matt Spinlerf1b46ff2020-01-22 14:10:04 -0600216size_t PEL::size() const
217{
218 size_t size = 0;
219
220 if (_ph)
221 {
222 size += _ph->header().size;
223 }
224
225 if (_uh)
226 {
227 size += _uh->header().size;
228 }
229
230 for (const auto& section : _optionalSections)
231 {
232 size += section->header().size;
233 }
234
235 return size;
236}
237
Matt Spinlerbd716f02019-10-15 10:54:11 -0500238std::optional<SRC*> PEL::primarySRC() const
239{
240 auto src = std::find_if(
241 _optionalSections.begin(), _optionalSections.end(), [](auto& section) {
242 return section->header().id ==
243 static_cast<uint16_t>(SectionID::primarySRC);
244 });
245 if (src != _optionalSections.end())
246 {
247 return static_cast<SRC*>(src->get());
248 }
249
250 return std::nullopt;
251}
252
Matt Spinlerf1e85e22019-11-01 11:31:31 -0500253void PEL::checkRulesAndFix()
254{
255 auto [actionFlags, eventType] =
256 pel_rules::check(_uh->actionFlags(), _uh->eventType(), _uh->severity());
257
258 _uh->setActionFlags(actionFlags);
259 _uh->setEventType(eventType);
260}
261
Matt Spinleracb7c102020-01-10 13:49:22 -0600262void PEL::printSectionInJSON(const Section& section, std::string& buf,
Harisuddin Mohamed Isaa214ed32020-02-28 15:58:23 +0800263 std::map<uint16_t, size_t>& pluralSections,
264 message::Registry& registry) const
Aatir186ce8c2019-10-20 15:13:39 -0500265{
266 char tmpB[5];
Aatir Manzurad0e0472019-10-07 13:18:37 -0500267 uint8_t id[] = {static_cast<uint8_t>(section.header().id >> 8),
268 static_cast<uint8_t>(section.header().id)};
269 sprintf(tmpB, "%c%c", id[0], id[1]);
270 std::string sectionID(tmpB);
271 std::string sectionName = pv::sectionTitles.count(sectionID)
272 ? pv::sectionTitles.at(sectionID)
273 : "Unknown Section";
Matt Spinleracb7c102020-01-10 13:49:22 -0600274
275 // Add a count if there are multiple of this type of section
276 auto count = pluralSections.find(section.header().id);
277 if (count != pluralSections.end())
278 {
279 sectionName += " " + std::to_string(count->second);
280 count->second++;
281 }
282
Aatir186ce8c2019-10-20 15:13:39 -0500283 if (section.valid())
284 {
Harisuddin Mohamed Isaa214ed32020-02-28 15:58:23 +0800285 auto json = (sectionID == "PS" || sectionID == "SS")
286 ? section.getJSON(registry)
287 : section.getJSON();
Matt Spinler4220a152020-03-26 10:18:09 -0500288
289 buf += "\"" + sectionName + "\": {\n";
290
Aatir Manzurad0e0472019-10-07 13:18:37 -0500291 if (json)
292 {
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800293 buf += *json + "\n},\n";
Aatir Manzurad0e0472019-10-07 13:18:37 -0500294 }
295 else
296 {
Matt Spinler4220a152020-03-26 10:18:09 -0500297 jsonInsert(buf, pv::sectionVer,
298 getNumberString("%d", section.header().version), 1);
299 jsonInsert(buf, pv::subSection,
300 getNumberString("%d", section.header().subType), 1);
301 jsonInsert(buf, pv::createdBy,
302 getNumberString("0x%X", section.header().componentID),
303 1);
304
Aatir Manzurad0e0472019-10-07 13:18:37 -0500305 std::vector<uint8_t> data;
306 Stream s{data};
307 section.flatten(s);
Matt Spinler4220a152020-03-26 10:18:09 -0500308 std::string dstr =
309 dumpHex(std::data(data) + SectionHeader::flattenedSize(),
310 data.size(), 2);
311
312 std::string jsonIndent(indentLevel, 0x20);
313 buf += jsonIndent + "\"Data\": [\n";
314 buf += dstr;
315 buf += jsonIndent + "]\n";
316 buf += "},\n";
Aatir Manzurad0e0472019-10-07 13:18:37 -0500317 }
Aatir186ce8c2019-10-20 15:13:39 -0500318 }
319 else
320 {
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800321 buf += "\n\"Invalid Section\": [\n \"invalid\"\n],\n";
Aatir186ce8c2019-10-20 15:13:39 -0500322 }
323}
324
Matt Spinleracb7c102020-01-10 13:49:22 -0600325std::map<uint16_t, size_t> PEL::getPluralSections() const
326{
327 std::map<uint16_t, size_t> sectionCounts;
328
329 for (const auto& section : optionalSections())
330 {
331 if (sectionCounts.find(section->header().id) == sectionCounts.end())
332 {
333 sectionCounts[section->header().id] = 1;
334 }
335 else
336 {
337 sectionCounts[section->header().id]++;
338 }
339 }
340
341 std::map<uint16_t, size_t> sections;
342 for (const auto& [id, count] : sectionCounts)
343 {
344 if (count > 1)
345 {
346 // Start with 0 here and printSectionInJSON()
347 // will increment it as it goes.
348 sections.emplace(id, 0);
349 }
350 }
351
352 return sections;
353}
354
Harisuddin Mohamed Isaa214ed32020-02-28 15:58:23 +0800355void PEL::toJSON(message::Registry& registry) const
Aatir186ce8c2019-10-20 15:13:39 -0500356{
Matt Spinleracb7c102020-01-10 13:49:22 -0600357 auto sections = getPluralSections();
358
Harisuddin Mohamed Isaa214ed32020-02-28 15:58:23 +0800359 std::string buf = "{\n";
360 printSectionInJSON(*(_ph.get()), buf, sections, registry);
361 printSectionInJSON(*(_uh.get()), buf, sections, registry);
Aatir186ce8c2019-10-20 15:13:39 -0500362 for (auto& section : this->optionalSections())
363 {
Harisuddin Mohamed Isaa214ed32020-02-28 15:58:23 +0800364 printSectionInJSON(*(section.get()), buf, sections, registry);
Aatir186ce8c2019-10-20 15:13:39 -0500365 }
366 buf += "}";
367 std::size_t found = buf.rfind(",");
368 if (found != std::string::npos)
369 buf.replace(found, 1, "");
370 std::cout << buf << std::endl;
371}
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800372
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600373namespace util
374{
375
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600376std::unique_ptr<UserData> makeJSONUserDataSection(const nlohmann::json& json)
377{
378 auto jsonString = json.dump();
379 std::vector<uint8_t> jsonData(jsonString.begin(), jsonString.end());
380
381 // Pad to a 4 byte boundary
382 while ((jsonData.size() % 4) != 0)
383 {
384 jsonData.push_back(0);
385 }
386
387 return std::make_unique<UserData>(
388 static_cast<uint16_t>(ComponentID::phosphorLogging),
389 static_cast<uint8_t>(UserDataFormat::json),
390 static_cast<uint8_t>(UserDataFormatVersion::json), jsonData);
391}
392
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600393std::unique_ptr<UserData> makeADUserDataSection(const AdditionalData& ad)
394{
395 assert(!ad.empty());
396 nlohmann::json json;
397
398 // Remove the 'ESEL' entry, as it contains a full PEL in the value.
399 if (ad.getValue("ESEL"))
400 {
401 auto newAD = ad;
402 newAD.remove("ESEL");
403 json = newAD.toJSON();
404 }
405 else
406 {
407 json = ad.toJSON();
408 }
409
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600410 return makeJSONUserDataSection(json);
411}
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600412
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600413void addProcessNameToJSON(nlohmann::json& json,
414 const std::optional<std::string>& pid,
415 const DataInterfaceBase& dataIface)
416{
Matt Spinler677381b2020-01-23 10:04:29 -0600417 std::string name{unknownValue};
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600418
419 try
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600420 {
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600421 if (pid)
422 {
423 auto n = dataIface.getProcessName(*pid);
424 if (n)
425 {
426 name = *n;
427 }
428 }
429 }
430 catch (std::exception& e)
431 {
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600432 }
433
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600434 json["Process Name"] = std::move(name);
435}
436
Matt Spinler677381b2020-01-23 10:04:29 -0600437void addBMCFWVersionIDToJSON(nlohmann::json& json,
438 const DataInterfaceBase& dataIface)
439{
440 auto id = dataIface.getBMCFWVersionID();
441 if (id.empty())
442 {
443 id = unknownValue;
444 }
445
446 json["BMC Version ID"] = std::move(id);
447}
448
Matt Spinler4aa23a12020-02-03 15:05:09 -0600449std::string lastSegment(char separator, std::string data)
450{
451 auto pos = data.find_last_of(separator);
452 if (pos != std::string::npos)
453 {
454 data = data.substr(pos + 1);
455 }
456
457 return data;
458}
459
460void addStatesToJSON(nlohmann::json& json, const DataInterfaceBase& dataIface)
461{
462 json["BMCState"] = lastSegment('.', dataIface.getBMCState());
463 json["ChassisState"] = lastSegment('.', dataIface.getChassisState());
464 json["HostState"] = lastSegment('.', dataIface.getHostState());
465}
466
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600467std::unique_ptr<UserData>
468 makeSysInfoUserDataSection(const AdditionalData& ad,
469 const DataInterfaceBase& dataIface)
470{
471 nlohmann::json json;
472
473 addProcessNameToJSON(json, ad.getValue("_PID"), dataIface);
Matt Spinler677381b2020-01-23 10:04:29 -0600474 addBMCFWVersionIDToJSON(json, dataIface);
Matt Spinler4aa23a12020-02-03 15:05:09 -0600475 addStatesToJSON(json, dataIface);
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600476
477 return makeJSONUserDataSection(json);
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600478}
479
Matt Spinler5b289b22020-03-26 14:27:19 -0500480std::vector<uint8_t> readFD(int fd)
481{
482 std::vector<uint8_t> data;
483
484 // Get the size
485 struct stat s;
486 int r = fstat(fd, &s);
487 if (r != 0)
488 {
489 auto e = errno;
490 log<level::ERR>("Could not get FFDC file size from FD",
491 entry("ERRNO=%d", e));
492 return data;
493 }
494
495 if (0 == s.st_size)
496 {
497 log<level::ERR>("FFDC file is empty");
498 return data;
499 }
500
501 data.resize(s.st_size);
502
503 // Make sure its at the beginning, as maybe another
504 // extension already used it.
505 r = lseek(fd, 0, SEEK_SET);
506 if (r == -1)
507 {
508 auto e = errno;
509 log<level::ERR>("Could not seek to beginning of FFDC file",
510 entry("ERRNO=%d", e));
511 return data;
512 }
513
514 r = read(fd, data.data(), s.st_size);
515 if (r == -1)
516 {
517 auto e = errno;
518 log<level::ERR>("Could not read FFDC file", entry("ERRNO=%d", e));
519 }
520 else if (r != s.st_size)
521 {
522 log<level::WARNING>("Could not read full FFDC file",
523 entry("FILE_SIZE=%d", s.st_size),
524 entry("SIZE_READ=%d", r));
525 }
526
527 return data;
528}
529
Matt Spinler56ad2a02020-03-26 14:00:52 -0500530std::unique_ptr<UserData> makeFFDCuserDataSection(uint16_t componentID,
531 const PelFFDCfile& file)
532{
Matt Spinler5b289b22020-03-26 14:27:19 -0500533 auto data = readFD(file.fd);
534
535 if (data.empty())
536 {
537 return std::unique_ptr<UserData>();
538 }
539
540 // The data needs 4 Byte alignment, and save amount padded for the
541 // CBOR case.
542 uint32_t pad = 0;
543 while (data.size() % 4)
544 {
545 data.push_back(0);
546 pad++;
547 }
548
549 // For JSON, CBOR, and Text use our component ID, subType, and version,
550 // otherwise use the supplied ones.
551 uint16_t compID = static_cast<uint16_t>(ComponentID::phosphorLogging);
552 uint8_t subType{};
553 uint8_t version{};
554
555 switch (file.format)
556 {
557 case UserDataFormat::json:
558 subType = static_cast<uint8_t>(UserDataFormat::json);
559 version = static_cast<uint8_t>(UserDataFormatVersion::json);
560 break;
561 case UserDataFormat::cbor:
562 subType = static_cast<uint8_t>(UserDataFormat::cbor);
563 version = static_cast<uint8_t>(UserDataFormatVersion::cbor);
564
565 // The CBOR parser will fail on the extra pad bytes since they
566 // aren't CBOR. Add the amount we padded to the end and other
567 // code will remove it all before parsing.
568 {
569 data.resize(data.size() + 4);
570 Stream stream{data};
571 stream.offset(data.size() - 4);
572 stream << pad;
573 }
574
575 break;
576 case UserDataFormat::text:
577 subType = static_cast<uint8_t>(UserDataFormat::text);
578 version = static_cast<uint8_t>(UserDataFormatVersion::text);
579 break;
580 case UserDataFormat::custom:
581 default:
582 // Use the passed in values
583 compID = componentID;
584 subType = file.subType;
585 version = file.version;
586 break;
587 }
588
589 return std::make_unique<UserData>(compID, subType, version, data);
Matt Spinler56ad2a02020-03-26 14:00:52 -0500590}
591
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600592} // namespace util
593
Matt Spinlercb6b0592019-07-16 15:58:51 -0500594} // namespace pels
595} // namespace openpower