blob: 541c392a3103f0bb2139914e72f1dc4cc0214ec8 [file] [log] [blame]
Alexander Hansen40fb5492025-10-28 17:56:12 +01001// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright 2019 IBM Corporation
3
Matt Spinlerc63e2e82019-12-02 15:50:12 -06004#include "extended_user_header.hpp"
5
Harisuddin Mohamed Isa160c51c2020-02-13 23:42:20 +08006#include "json_utils.hpp"
Matt Spinlerc63e2e82019-12-02 15:50:12 -06007#include "pel_types.hpp"
Harisuddin Mohamed Isabebeb942020-03-12 17:12:24 +08008#include "pel_values.hpp"
Matt Spinlerc63e2e82019-12-02 15:50:12 -06009
Arya K Padman5bc26532024-04-10 06:19:25 -050010#include <phosphor-logging/lg2.hpp>
Matt Spinlerc63e2e82019-12-02 15:50:12 -060011
12namespace openpower
13{
14namespace pels
15{
16
Harisuddin Mohamed Isabebeb942020-03-12 17:12:24 +080017namespace pv = openpower::pels::pel_values;
Arya K Padman5bc26532024-04-10 06:19:25 -050018
Matt Spinlerc63e2e82019-12-02 15:50:12 -060019const size_t defaultSymptomIDWord = 3;
20const size_t symptomIDMaxSize = 80;
21
22ExtendedUserHeader::ExtendedUserHeader(Stream& pel)
23{
24 try
25 {
26 unflatten(pel);
27 validate();
28 }
29 catch (const std::exception& e)
30 {
Arya K Padman5bc26532024-04-10 06:19:25 -050031 lg2::error("Cannot unflatten extended user header: {EXCEPTION}",
32 "EXCEPTION", e);
Matt Spinlerc63e2e82019-12-02 15:50:12 -060033 _valid = false;
34 }
35}
36
37ExtendedUserHeader::ExtendedUserHeader(const DataInterfaceBase& dataIface,
38 const message::Entry& regEntry,
39 const SRC& src) :
40 _mtms(dataIface.getMachineTypeModel(), dataIface.getMachineSerialNumber())
41{
42 _header.id = static_cast<uint16_t>(SectionID::extendedUserHeader);
43 _header.version = extendedUserHeaderVersion;
44 _header.subType = 0;
45 _header.componentID = static_cast<uint16_t>(ComponentID::phosphorLogging);
46
47 memset(_serverFWVersion.data(), 0, _serverFWVersion.size());
48 auto version = dataIface.getServerFWVersion();
49
50 // The last byte must always be the NULL terminator
51 for (size_t i = 0; i < version.size() && i < firmwareVersionSize - 1; i++)
52 {
53 _serverFWVersion[i] = version[i];
54 }
55
56 memset(_subsystemFWVersion.data(), 0, _subsystemFWVersion.size());
57 version = dataIface.getBMCFWVersion();
58
59 // The last byte must always be the NULL terminator
60 for (size_t i = 0; i < version.size() && i < firmwareVersionSize - 1; i++)
61 {
62 _subsystemFWVersion[i] = version[i];
63 }
64
65 createSymptomID(regEntry, src);
66
67 _header.size = flattenedSize();
68 _valid = true;
69}
70
71void ExtendedUserHeader::flatten(Stream& pel) const
72{
73 pel << _header << _mtms;
74 pel.write(_serverFWVersion.data(), _serverFWVersion.size());
75 pel.write(_subsystemFWVersion.data(), _subsystemFWVersion.size());
76 pel << _reserved4B << _refTime << _reserved1B1 << _reserved1B2
77 << _reserved1B3 << _symptomIDSize << _symptomID;
78}
79
80void ExtendedUserHeader::unflatten(Stream& pel)
81{
82 pel >> _header >> _mtms;
83 pel.read(_serverFWVersion.data(), _serverFWVersion.size());
84 pel.read(_subsystemFWVersion.data(), _subsystemFWVersion.size());
85 pel >> _reserved4B >> _refTime >> _reserved1B1 >> _reserved1B2 >>
86 _reserved1B3 >> _symptomIDSize;
87
88 _symptomID.resize(_symptomIDSize);
89 pel >> _symptomID;
90}
91
92void ExtendedUserHeader::validate()
93{
94 bool failed = false;
95
96 if (header().id != static_cast<uint16_t>(SectionID::extendedUserHeader))
97 {
Arya K Padman5bc26532024-04-10 06:19:25 -050098 lg2::error("Invalid ExtendedUserHeader section ID: {HEADER_ID}",
99 "HEADER_ID", lg2::hex, header().id);
Matt Spinlerc63e2e82019-12-02 15:50:12 -0600100 failed = true;
101 }
102
103 if (header().version != extendedUserHeaderVersion)
104 {
Arya K Padman5bc26532024-04-10 06:19:25 -0500105 lg2::error("Invalid ExtendedUserHeader version: {HEADER_VERSION}",
106 "HEADER_VERSION", lg2::hex, header().version);
Matt Spinlerc63e2e82019-12-02 15:50:12 -0600107 failed = true;
108 }
109
110 _valid = (failed) ? false : true;
111}
112
113void ExtendedUserHeader::createSymptomID(const message::Entry& regEntry,
114 const SRC& src)
115{
116 // Contains the first 8 characters of the ASCII string plus additional
117 // words from the SRC, separated by underscores. The message registry
118 // says which words to use, though that's optional and if not present
119 // then use a default word.
120 std::vector<size_t> idWords;
121
122 if (regEntry.src.symptomID)
123 {
124 idWords = regEntry.src.symptomID.value();
125 }
126 else
127 {
128 idWords.push_back(defaultSymptomIDWord);
129 }
130
131 auto symptomID = src.asciiString().substr(0, 8);
132
133 const auto& hexWords = src.hexwordData();
134
135 for (auto wordNum : idWords)
136 {
137 symptomID.push_back('_');
138
139 // Get the hexword array index for this SRC word
140 auto index = src.getWordIndexFromWordNum(wordNum);
141
142 // Convert to ASCII
143 char word[20];
144 sprintf(word, "%08X", hexWords[index]);
145 symptomID += word;
146 }
147
148 std::copy(symptomID.begin(), symptomID.end(),
149 std::back_inserter(_symptomID));
150
151 // Max total size is 80, including the upcoming NULL
152 if (_symptomID.size() > (symptomIDMaxSize - 1))
153 {
154 _symptomID.resize(symptomIDMaxSize - 1);
155 }
156
157 // NULL terminated
158 _symptomID.push_back(0);
159
160 // PAD with NULLs to a 4 byte boundary
161 while ((_symptomID.size() % 4) != 0)
162 {
163 _symptomID.push_back(0);
164 }
165
166 _symptomIDSize = _symptomID.size();
167}
168
Matt Spinlerb832aa52023-03-21 15:32:34 -0500169std::optional<std::string> ExtendedUserHeader::getJSON(uint8_t creatorID) const
Harisuddin Mohamed Isa160c51c2020-02-13 23:42:20 +0800170{
171 std::string json;
Harisuddin Mohamed Isabebeb942020-03-12 17:12:24 +0800172 jsonInsert(json, pv::sectionVer, getNumberString("%d", _header.version), 1);
173 jsonInsert(json, pv::subSection, getNumberString("%d", _header.subType), 1);
174 jsonInsert(json, pv::createdBy,
Matt Spinlerb832aa52023-03-21 15:32:34 -0500175 getComponentName(_header.componentID, creatorID), 1);
Harisuddin Mohamed Isa160c51c2020-02-13 23:42:20 +0800176 jsonInsert(json, "Reporting Machine Type", machineTypeModel(), 1);
177 jsonInsert(json, "Reporting Serial Number", trimEnd(machineSerialNumber()),
178 1);
179 jsonInsert(json, "FW Released Ver", serverFWVersion(), 1);
180 jsonInsert(json, "FW SubSys Version", subsystemFWVersion(), 1);
181 jsonInsert(json, "Common Ref Time",
182 getNumberString("%02X", _refTime.month) + '/' +
183 getNumberString("%02X", _refTime.day) + '/' +
184 getNumberString("%02X", _refTime.yearMSB) +
185 getNumberString("%02X", _refTime.yearLSB) + ' ' +
186 getNumberString("%02X", _refTime.hour) + ':' +
187 getNumberString("%02X", _refTime.minutes) + ':' +
188 getNumberString("%02X", _refTime.seconds),
189 1);
190 jsonInsert(json, "Symptom Id Len", getNumberString("%d", _symptomIDSize),
191 1);
192 jsonInsert(json, "Symptom Id", symptomID(), 1);
193 json.erase(json.size() - 2);
194 return json;
195}
196
Matt Spinlerc63e2e82019-12-02 15:50:12 -0600197} // namespace pels
198} // namespace openpower