blob: 18676731ab7833e98e189e2e19856ccef89d543b [file] [log] [blame]
Matt Spinlerc63e2e82019-12-02 15:50:12 -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 */
16#include "extended_user_header.hpp"
17
Harisuddin Mohamed Isa160c51c2020-02-13 23:42:20 +080018#include "json_utils.hpp"
Matt Spinlerc63e2e82019-12-02 15:50:12 -060019#include "pel_types.hpp"
Harisuddin Mohamed Isabebeb942020-03-12 17:12:24 +080020#include "pel_values.hpp"
Matt Spinlerc63e2e82019-12-02 15:50:12 -060021
22#include <phosphor-logging/log.hpp>
23
Jayanth Othayoth1aa90d42023-09-13 04:25:45 -050024#include <format>
25
Matt Spinlerc63e2e82019-12-02 15:50:12 -060026namespace openpower
27{
28namespace pels
29{
30
Harisuddin Mohamed Isabebeb942020-03-12 17:12:24 +080031namespace pv = openpower::pels::pel_values;
Matt Spinlerc63e2e82019-12-02 15:50:12 -060032using namespace phosphor::logging;
33const size_t defaultSymptomIDWord = 3;
34const size_t symptomIDMaxSize = 80;
35
36ExtendedUserHeader::ExtendedUserHeader(Stream& pel)
37{
38 try
39 {
40 unflatten(pel);
41 validate();
42 }
43 catch (const std::exception& e)
44 {
Matt Spinler8ac20502023-01-04 11:03:58 -060045 log<level::ERR>(
Jayanth Othayoth1aa90d42023-09-13 04:25:45 -050046 std::format("Cannot unflatten extended user header: {}", e.what())
Matt Spinler8ac20502023-01-04 11:03:58 -060047 .c_str());
Matt Spinlerc63e2e82019-12-02 15:50:12 -060048 _valid = false;
49 }
50}
51
52ExtendedUserHeader::ExtendedUserHeader(const DataInterfaceBase& dataIface,
53 const message::Entry& regEntry,
54 const SRC& src) :
55 _mtms(dataIface.getMachineTypeModel(), dataIface.getMachineSerialNumber())
56{
57 _header.id = static_cast<uint16_t>(SectionID::extendedUserHeader);
58 _header.version = extendedUserHeaderVersion;
59 _header.subType = 0;
60 _header.componentID = static_cast<uint16_t>(ComponentID::phosphorLogging);
61
62 memset(_serverFWVersion.data(), 0, _serverFWVersion.size());
63 auto version = dataIface.getServerFWVersion();
64
65 // The last byte must always be the NULL terminator
66 for (size_t i = 0; i < version.size() && i < firmwareVersionSize - 1; i++)
67 {
68 _serverFWVersion[i] = version[i];
69 }
70
71 memset(_subsystemFWVersion.data(), 0, _subsystemFWVersion.size());
72 version = dataIface.getBMCFWVersion();
73
74 // The last byte must always be the NULL terminator
75 for (size_t i = 0; i < version.size() && i < firmwareVersionSize - 1; i++)
76 {
77 _subsystemFWVersion[i] = version[i];
78 }
79
80 createSymptomID(regEntry, src);
81
82 _header.size = flattenedSize();
83 _valid = true;
84}
85
86void ExtendedUserHeader::flatten(Stream& pel) const
87{
88 pel << _header << _mtms;
89 pel.write(_serverFWVersion.data(), _serverFWVersion.size());
90 pel.write(_subsystemFWVersion.data(), _subsystemFWVersion.size());
91 pel << _reserved4B << _refTime << _reserved1B1 << _reserved1B2
92 << _reserved1B3 << _symptomIDSize << _symptomID;
93}
94
95void ExtendedUserHeader::unflatten(Stream& pel)
96{
97 pel >> _header >> _mtms;
98 pel.read(_serverFWVersion.data(), _serverFWVersion.size());
99 pel.read(_subsystemFWVersion.data(), _subsystemFWVersion.size());
100 pel >> _reserved4B >> _refTime >> _reserved1B1 >> _reserved1B2 >>
101 _reserved1B3 >> _symptomIDSize;
102
103 _symptomID.resize(_symptomIDSize);
104 pel >> _symptomID;
105}
106
107void ExtendedUserHeader::validate()
108{
109 bool failed = false;
110
111 if (header().id != static_cast<uint16_t>(SectionID::extendedUserHeader))
112 {
Matt Spinler8ac20502023-01-04 11:03:58 -0600113 log<level::ERR>(
Jayanth Othayoth1aa90d42023-09-13 04:25:45 -0500114 std::format("Invalid ExtendedUserHeader section ID: {0:#x}",
Matt Spinler8ac20502023-01-04 11:03:58 -0600115 header().id)
116 .c_str());
Matt Spinlerc63e2e82019-12-02 15:50:12 -0600117 failed = true;
118 }
119
120 if (header().version != extendedUserHeaderVersion)
121 {
Matt Spinler8ac20502023-01-04 11:03:58 -0600122 log<level::ERR>(
Jayanth Othayoth1aa90d42023-09-13 04:25:45 -0500123 std::format("Invalid ExtendedUserHeader version: {0:#x}",
Matt Spinler8ac20502023-01-04 11:03:58 -0600124 header().version)
125 .c_str());
Matt Spinlerc63e2e82019-12-02 15:50:12 -0600126 failed = true;
127 }
128
129 _valid = (failed) ? false : true;
130}
131
132void ExtendedUserHeader::createSymptomID(const message::Entry& regEntry,
133 const SRC& src)
134{
135 // Contains the first 8 characters of the ASCII string plus additional
136 // words from the SRC, separated by underscores. The message registry
137 // says which words to use, though that's optional and if not present
138 // then use a default word.
139 std::vector<size_t> idWords;
140
141 if (regEntry.src.symptomID)
142 {
143 idWords = regEntry.src.symptomID.value();
144 }
145 else
146 {
147 idWords.push_back(defaultSymptomIDWord);
148 }
149
150 auto symptomID = src.asciiString().substr(0, 8);
151
152 const auto& hexWords = src.hexwordData();
153
154 for (auto wordNum : idWords)
155 {
156 symptomID.push_back('_');
157
158 // Get the hexword array index for this SRC word
159 auto index = src.getWordIndexFromWordNum(wordNum);
160
161 // Convert to ASCII
162 char word[20];
163 sprintf(word, "%08X", hexWords[index]);
164 symptomID += word;
165 }
166
167 std::copy(symptomID.begin(), symptomID.end(),
168 std::back_inserter(_symptomID));
169
170 // Max total size is 80, including the upcoming NULL
171 if (_symptomID.size() > (symptomIDMaxSize - 1))
172 {
173 _symptomID.resize(symptomIDMaxSize - 1);
174 }
175
176 // NULL terminated
177 _symptomID.push_back(0);
178
179 // PAD with NULLs to a 4 byte boundary
180 while ((_symptomID.size() % 4) != 0)
181 {
182 _symptomID.push_back(0);
183 }
184
185 _symptomIDSize = _symptomID.size();
186}
187
Matt Spinlerb832aa52023-03-21 15:32:34 -0500188std::optional<std::string> ExtendedUserHeader::getJSON(uint8_t creatorID) const
Harisuddin Mohamed Isa160c51c2020-02-13 23:42:20 +0800189{
190 std::string json;
Harisuddin Mohamed Isabebeb942020-03-12 17:12:24 +0800191 jsonInsert(json, pv::sectionVer, getNumberString("%d", _header.version), 1);
192 jsonInsert(json, pv::subSection, getNumberString("%d", _header.subType), 1);
193 jsonInsert(json, pv::createdBy,
Matt Spinlerb832aa52023-03-21 15:32:34 -0500194 getComponentName(_header.componentID, creatorID), 1);
Harisuddin Mohamed Isa160c51c2020-02-13 23:42:20 +0800195 jsonInsert(json, "Reporting Machine Type", machineTypeModel(), 1);
196 jsonInsert(json, "Reporting Serial Number", trimEnd(machineSerialNumber()),
197 1);
198 jsonInsert(json, "FW Released Ver", serverFWVersion(), 1);
199 jsonInsert(json, "FW SubSys Version", subsystemFWVersion(), 1);
200 jsonInsert(json, "Common Ref Time",
201 getNumberString("%02X", _refTime.month) + '/' +
202 getNumberString("%02X", _refTime.day) + '/' +
203 getNumberString("%02X", _refTime.yearMSB) +
204 getNumberString("%02X", _refTime.yearLSB) + ' ' +
205 getNumberString("%02X", _refTime.hour) + ':' +
206 getNumberString("%02X", _refTime.minutes) + ':' +
207 getNumberString("%02X", _refTime.seconds),
208 1);
209 jsonInsert(json, "Symptom Id Len", getNumberString("%d", _symptomIDSize),
210 1);
211 jsonInsert(json, "Symptom Id", symptomID(), 1);
212 json.erase(json.size() - 2);
213 return json;
214}
215
Matt Spinlerc63e2e82019-12-02 15:50:12 -0600216} // namespace pels
217} // namespace openpower