xref: /openbmc/phosphor-logging/extensions/openpower-pels/extended_user_header.cpp (revision 40fb54935ce7367636a7156039396ee91cc4d5e2)
1 // SPDX-License-Identifier: Apache-2.0
2 // SPDX-FileCopyrightText: Copyright 2019 IBM Corporation
3 
4 #include "extended_user_header.hpp"
5 
6 #include "json_utils.hpp"
7 #include "pel_types.hpp"
8 #include "pel_values.hpp"
9 
10 #include <phosphor-logging/lg2.hpp>
11 
12 namespace openpower
13 {
14 namespace pels
15 {
16 
17 namespace pv = openpower::pels::pel_values;
18 
19 const size_t defaultSymptomIDWord = 3;
20 const size_t symptomIDMaxSize = 80;
21 
ExtendedUserHeader(Stream & pel)22 ExtendedUserHeader::ExtendedUserHeader(Stream& pel)
23 {
24     try
25     {
26         unflatten(pel);
27         validate();
28     }
29     catch (const std::exception& e)
30     {
31         lg2::error("Cannot unflatten extended user header: {EXCEPTION}",
32                    "EXCEPTION", e);
33         _valid = false;
34     }
35 }
36 
ExtendedUserHeader(const DataInterfaceBase & dataIface,const message::Entry & regEntry,const SRC & src)37 ExtendedUserHeader::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 
flatten(Stream & pel) const71 void 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 
unflatten(Stream & pel)80 void 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 
validate()92 void ExtendedUserHeader::validate()
93 {
94     bool failed = false;
95 
96     if (header().id != static_cast<uint16_t>(SectionID::extendedUserHeader))
97     {
98         lg2::error("Invalid ExtendedUserHeader section ID: {HEADER_ID}",
99                    "HEADER_ID", lg2::hex, header().id);
100         failed = true;
101     }
102 
103     if (header().version != extendedUserHeaderVersion)
104     {
105         lg2::error("Invalid ExtendedUserHeader version: {HEADER_VERSION}",
106                    "HEADER_VERSION", lg2::hex, header().version);
107         failed = true;
108     }
109 
110     _valid = (failed) ? false : true;
111 }
112 
createSymptomID(const message::Entry & regEntry,const SRC & src)113 void 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 
getJSON(uint8_t creatorID) const169 std::optional<std::string> ExtendedUserHeader::getJSON(uint8_t creatorID) const
170 {
171     std::string json;
172     jsonInsert(json, pv::sectionVer, getNumberString("%d", _header.version), 1);
173     jsonInsert(json, pv::subSection, getNumberString("%d", _header.subType), 1);
174     jsonInsert(json, pv::createdBy,
175                getComponentName(_header.componentID, creatorID), 1);
176     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 
197 } // namespace pels
198 } // namespace openpower
199