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