1 /**
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 "user_header.hpp"
17 
18 #include "json_utils.hpp"
19 #include "pel_types.hpp"
20 #include "pel_values.hpp"
21 #include "severity.hpp"
22 
23 #include <iostream>
24 #include <phosphor-logging/log.hpp>
25 
26 namespace openpower
27 {
28 namespace pels
29 {
30 
31 namespace pv = openpower::pels::pel_values;
32 using namespace phosphor::logging;
33 
34 void UserHeader::unflatten(Stream& stream)
35 {
36     stream >> _header >> _eventSubsystem >> _eventScope >> _eventSeverity >>
37         _eventType >> _reserved4Byte1 >> _problemDomain >> _problemVector >>
38         _actionFlags >> _states;
39 }
40 
41 void UserHeader::flatten(Stream& stream) const
42 {
43     stream << _header << _eventSubsystem << _eventScope << _eventSeverity
44            << _eventType << _reserved4Byte1 << _problemDomain << _problemVector
45            << _actionFlags << _states;
46 }
47 
48 UserHeader::UserHeader(const message::Entry& entry,
49                        phosphor::logging::Entry::Level severity,
50                        const DataInterfaceBase& dataIface)
51 {
52     _header.id = static_cast<uint16_t>(SectionID::userHeader);
53     _header.size = UserHeader::flattenedSize();
54     _header.version = userHeaderVersion;
55     _header.subType = 0;
56     _header.componentID = static_cast<uint16_t>(ComponentID::phosphorLogging);
57 
58     _eventSubsystem = entry.subsystem;
59 
60     _eventScope = entry.eventScope.value_or(
61         static_cast<uint8_t>(EventScope::entirePlatform));
62 
63     // Get the severity from the registry if it's there, otherwise get it
64     // from the OpenBMC event log severity value.
65     if (!entry.severity)
66     {
67         _eventSeverity = convertOBMCSeverityToPEL(severity);
68     }
69     else
70     {
71         // Find the severity possibly dependent on the system type.
72         auto sev =
73             getSeverity(entry.severity.value(), dataIface.getSystemNames());
74         if (sev)
75         {
76             _eventSeverity = *sev;
77         }
78         else
79         {
80             // Someone screwed up the message registry.
81             std::string types;
82             const auto& compatibles = dataIface.getSystemNames();
83             std::for_each(compatibles.begin(), compatibles.end(),
84                           [&types](const auto& t) { types += t + '|'; });
85 
86             log<level::ERR>(
87                 "No severity entry found for this error and system name",
88                 phosphor::logging::entry("ERROR=%s", entry.name.c_str()),
89                 phosphor::logging::entry("SYSTEMNAMES=%s", types.c_str()));
90 
91             // Have to choose something, just use informational.
92             _eventSeverity = 0;
93         }
94     }
95 
96     // TODO: ibm-dev/dev/#1144 Handle manufacturing sev & action flags
97 
98     if (entry.eventType)
99     {
100         _eventType = *entry.eventType;
101     }
102     else
103     {
104         // There are different default event types for info errors
105         // vs non info ones.
106         auto sevType = static_cast<SeverityType>(_eventSeverity & 0xF0);
107 
108         _eventType = (sevType == SeverityType::nonError)
109                          ? static_cast<uint8_t>(EventType::miscInformational)
110                          : static_cast<uint8_t>(EventType::notApplicable);
111     }
112 
113     _reserved4Byte1 = 0;
114 
115     // No uses for problem domain or vector
116     _problemDomain = 0;
117     _problemVector = 0;
118 
119     // These will be set in pel_rules::check() if they're still
120     // at the default value.
121     _actionFlags = entry.actionFlags.value_or(actionFlagsDefault);
122 
123     _states = 0;
124 
125     _valid = true;
126 }
127 
128 UserHeader::UserHeader(Stream& pel)
129 {
130     try
131     {
132         unflatten(pel);
133         validate();
134     }
135     catch (const std::exception& e)
136     {
137         log<level::ERR>("Cannot unflatten user header",
138                         entry("ERROR=%s", e.what()));
139         _valid = false;
140     }
141 }
142 
143 void UserHeader::validate()
144 {
145     bool failed = false;
146     if (header().id != static_cast<uint16_t>(SectionID::userHeader))
147     {
148         log<level::ERR>("Invalid user header section ID",
149                         entry("ID=0x%X", header().id));
150         failed = true;
151     }
152 
153     if (header().version != userHeaderVersion)
154     {
155         log<level::ERR>("Invalid user header version",
156                         entry("VERSION=0x%X", header().version));
157         failed = true;
158     }
159 
160     _valid = (failed) ? false : true;
161 }
162 
163 std::optional<std::string> UserHeader::getJSON() const
164 {
165     std::string severity;
166     std::string subsystem;
167     std::string eventScope;
168     std::string eventType;
169     std::vector<std::string> actionFlags;
170     severity = pv::getValue(_eventSeverity, pel_values::severityValues);
171     subsystem = pv::getValue(_eventSubsystem, pel_values::subsystemValues);
172     eventScope = pv::getValue(_eventScope, pel_values::eventScopeValues);
173     eventType = pv::getValue(_eventType, pel_values::eventTypeValues);
174     actionFlags =
175         pv::getValuesBitwise(_actionFlags, pel_values::actionFlagsValues);
176 
177     std::string hostState{"Invalid"};
178     auto iter = pv::transmissionStates.find(
179         static_cast<TransmissionState>(hostTransmissionState()));
180     if (iter != pv::transmissionStates.end())
181     {
182         hostState = iter->second;
183     }
184 
185     std::string uh;
186     jsonInsert(uh, pv::sectionVer, getNumberString("%d", userHeaderVersion), 1);
187     jsonInsert(uh, pv::subSection, getNumberString("%d", _header.subType), 1);
188     jsonInsert(uh, "Log Committed by",
189                getNumberString("0x%X", _header.componentID), 1);
190     jsonInsert(uh, "Subsystem", subsystem, 1);
191     jsonInsert(uh, "Event Scope", eventScope, 1);
192     jsonInsert(uh, "Event Severity", severity, 1);
193     jsonInsert(uh, "Event Type", eventType, 1);
194     jsonInsertArray(uh, "Action Flags", actionFlags, 1);
195     jsonInsert(uh, "Host Transmission", hostState, 1);
196     uh.erase(uh.size() - 2);
197     return uh;
198 }
199 
200 std::optional<uint8_t> UserHeader::getSeverity(
201     const std::vector<message::RegistrySeverity>& severities,
202     const std::vector<std::string>& systemNames) const
203 {
204     const uint8_t* s = nullptr;
205 
206     // Find the severity to use for this system type, or use the default
207     // entry (where no system type is specified).
208     for (const auto& sev : severities)
209     {
210         if (std::find(systemNames.begin(), systemNames.end(), sev.system) !=
211             systemNames.end())
212         {
213             s = &sev.severity;
214             break;
215         }
216         else if (sev.system.empty())
217         {
218             s = &sev.severity;
219         }
220     }
221 
222     if (s)
223     {
224         return *s;
225     }
226 
227     return std::nullopt;
228 }
229 
230 } // namespace pels
231 } // namespace openpower
232