blob: c5c19386c72553fbae6cfe754356292409ffab9d [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
18#include "pel_types.hpp"
19
20#include <phosphor-logging/log.hpp>
21
22namespace openpower
23{
24namespace pels
25{
26
27using namespace phosphor::logging;
28const size_t defaultSymptomIDWord = 3;
29const size_t symptomIDMaxSize = 80;
30
31ExtendedUserHeader::ExtendedUserHeader(Stream& pel)
32{
33 try
34 {
35 unflatten(pel);
36 validate();
37 }
38 catch (const std::exception& e)
39 {
40 log<level::ERR>("Cannot unflatten extended user header",
41 entry("ERROR=%s", e.what()));
42 _valid = false;
43 }
44}
45
46ExtendedUserHeader::ExtendedUserHeader(const DataInterfaceBase& dataIface,
47 const message::Entry& regEntry,
48 const SRC& src) :
49 _mtms(dataIface.getMachineTypeModel(), dataIface.getMachineSerialNumber())
50{
51 _header.id = static_cast<uint16_t>(SectionID::extendedUserHeader);
52 _header.version = extendedUserHeaderVersion;
53 _header.subType = 0;
54 _header.componentID = static_cast<uint16_t>(ComponentID::phosphorLogging);
55
56 memset(_serverFWVersion.data(), 0, _serverFWVersion.size());
57 auto version = dataIface.getServerFWVersion();
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 _serverFWVersion[i] = version[i];
63 }
64
65 memset(_subsystemFWVersion.data(), 0, _subsystemFWVersion.size());
66 version = dataIface.getBMCFWVersion();
67
68 // The last byte must always be the NULL terminator
69 for (size_t i = 0; i < version.size() && i < firmwareVersionSize - 1; i++)
70 {
71 _subsystemFWVersion[i] = version[i];
72 }
73
74 createSymptomID(regEntry, src);
75
76 _header.size = flattenedSize();
77 _valid = true;
78}
79
80void ExtendedUserHeader::flatten(Stream& pel) const
81{
82 pel << _header << _mtms;
83 pel.write(_serverFWVersion.data(), _serverFWVersion.size());
84 pel.write(_subsystemFWVersion.data(), _subsystemFWVersion.size());
85 pel << _reserved4B << _refTime << _reserved1B1 << _reserved1B2
86 << _reserved1B3 << _symptomIDSize << _symptomID;
87}
88
89void ExtendedUserHeader::unflatten(Stream& pel)
90{
91 pel >> _header >> _mtms;
92 pel.read(_serverFWVersion.data(), _serverFWVersion.size());
93 pel.read(_subsystemFWVersion.data(), _subsystemFWVersion.size());
94 pel >> _reserved4B >> _refTime >> _reserved1B1 >> _reserved1B2 >>
95 _reserved1B3 >> _symptomIDSize;
96
97 _symptomID.resize(_symptomIDSize);
98 pel >> _symptomID;
99}
100
101void ExtendedUserHeader::validate()
102{
103 bool failed = false;
104
105 if (header().id != static_cast<uint16_t>(SectionID::extendedUserHeader))
106 {
107 log<level::ERR>("Invalid failing Extended User Header section ID",
108 entry("ID=0x%X", header().id));
109 failed = true;
110 }
111
112 if (header().version != extendedUserHeaderVersion)
113 {
114 log<level::ERR>("Invalid Extended User Header version",
115 entry("VERSION=0x%X", header().version));
116 failed = true;
117 }
118
119 _valid = (failed) ? false : true;
120}
121
122void ExtendedUserHeader::createSymptomID(const message::Entry& regEntry,
123 const SRC& src)
124{
125 // Contains the first 8 characters of the ASCII string plus additional
126 // words from the SRC, separated by underscores. The message registry
127 // says which words to use, though that's optional and if not present
128 // then use a default word.
129 std::vector<size_t> idWords;
130
131 if (regEntry.src.symptomID)
132 {
133 idWords = regEntry.src.symptomID.value();
134 }
135 else
136 {
137 idWords.push_back(defaultSymptomIDWord);
138 }
139
140 auto symptomID = src.asciiString().substr(0, 8);
141
142 const auto& hexWords = src.hexwordData();
143
144 for (auto wordNum : idWords)
145 {
146 symptomID.push_back('_');
147
148 // Get the hexword array index for this SRC word
149 auto index = src.getWordIndexFromWordNum(wordNum);
150
151 // Convert to ASCII
152 char word[20];
153 sprintf(word, "%08X", hexWords[index]);
154 symptomID += word;
155 }
156
157 std::copy(symptomID.begin(), symptomID.end(),
158 std::back_inserter(_symptomID));
159
160 // Max total size is 80, including the upcoming NULL
161 if (_symptomID.size() > (symptomIDMaxSize - 1))
162 {
163 _symptomID.resize(symptomIDMaxSize - 1);
164 }
165
166 // NULL terminated
167 _symptomID.push_back(0);
168
169 // PAD with NULLs to a 4 byte boundary
170 while ((_symptomID.size() % 4) != 0)
171 {
172 _symptomID.push_back(0);
173 }
174
175 _symptomIDSize = _symptomID.size();
176}
177
178} // namespace pels
179} // namespace openpower