xref: /openbmc/phosphor-logging/extensions/openpower-pels/registry.hpp (revision d8e29000ac63f8eb5fd5ed4fe6278c256c370335)
1 #pragma once
2 #include <filesystem>
3 #include <nlohmann/json.hpp>
4 #include <optional>
5 #include <string>
6 #include <vector>
7 
8 namespace openpower
9 {
10 namespace pels
11 {
12 namespace message
13 {
14 
15 constexpr auto registryFileName = "message_registry.json";
16 enum class LookupType
17 {
18     name = 0,
19     reasonCode = 1
20 };
21 
22 /**
23  * @brief Represents the Documentation related fields in the message registry.
24  *        It is part of the 'Entry' structure that will be filled in when
25  *        an error is looked up in the registry.
26  *
27  * If a field is wrapped by std::optional, it means the field is
28  * optional in the JSON and higher level code knows how to handle it.
29  */
30 struct DOC
31 {
32     /**
33      * @brief Description of error
34      */
35     std::string description;
36 
37     /**
38      * @brief Error message field
39      */
40     std::string message;
41 
42     /**
43      * @brief An optional vector of SRC word 6-9 to use as the source of the
44      *        numeric arguments that will be substituted into any placeholder
45      *        in the Message field.
46      */
47     std::optional<std::vector<std::string>> messageArgSources;
48 };
49 
50 /**
51  * @brief Represents the SRC related fields in the message registry.
52  *        It is part of the 'Entry' structure that will be filled in when
53  *        an error is looked up in the registry.
54  *
55  * If a field is wrapped by std::optional, it means the field is
56  * optional in the JSON and higher level code knows how to handle it.
57  */
58 struct SRC
59 {
60     /**
61      * @brief SRC type - The first byte of the ASCII string
62      */
63     uint8_t type;
64 
65     /**
66      * @brief The SRC reason code (2nd half of 4B 'ASCII string' word)
67      */
68     uint16_t reasonCode;
69 
70     /**
71      * @brief Specifies if the SRC represents a power fault.  Optional.
72      */
73     std::optional<bool> powerFault;
74 
75     /**
76      * @brief An optional vector of SRC hexword numbers that should be used
77      *        along with the SRC ASCII string to build the Symptom ID, which
78      *        is a field in the Extended Header section.
79      */
80     using WordNum = size_t;
81     std::optional<std::vector<WordNum>> symptomID;
82 
83     /**
84      * @brief Which AdditionalData fields to use to fill in the user defined
85      *        SRC hexwords.
86      *
87      * For example, if the AdditionalData event log property contained
88      * "CHIPNUM=42" and this map contained {6, CHIPNUM}, then the code
89      * would put 42 into SRC hexword 6.
90      */
91     using AdditionalDataField = std::string;
92     std::optional<std::map<WordNum, AdditionalDataField>> hexwordADFields;
93 
94     SRC() : type(0), reasonCode(0)
95     {
96     }
97 };
98 
99 /**
100  * @brief Represents a message registry entry, which is used for creating a
101  *        PEL from an OpenBMC event log.
102  */
103 struct Entry
104 {
105     /**
106      * @brief The error name, like "xyz.openbmc_project.Error.Foo".
107      */
108     std::string name;
109 
110     /**
111      * @brief The component ID of the PEL creator.
112      */
113     uint16_t componentID;
114 
115     /**
116      * @brief The PEL subsystem field.
117      */
118     uint8_t subsystem;
119 
120     /**
121      * @brief The optional PEL severity field.  If not specified, the PEL
122      *        will use the severity of the OpenBMC event log.
123      */
124     std::optional<uint8_t> severity;
125 
126     /**
127      * @brief The optional severity field to use when in manufacturing tolerance
128      *        mode.
129      */
130     std::optional<uint8_t> mfgSeverity;
131 
132     /**
133      * @brief The PEL action flags field.
134      */
135     std::optional<uint16_t> actionFlags;
136 
137     /**
138      * @brief  The optional action flags to use instead when in manufacturing
139      * tolerance mode.
140      */
141     std::optional<uint16_t> mfgActionFlags;
142 
143     /**
144      * @brief The PEL event type field.  If not specified, higher level code
145      *        will decide the value.
146      */
147     std::optional<uint8_t> eventType;
148 
149     /**
150      * @brief The PEL event scope field.  If not specified, higher level code
151      *        will decide the value.
152      */
153     std::optional<uint8_t> eventScope;
154 
155     /**
156      * The SRC related fields.
157      */
158     SRC src;
159 
160     /**
161      * The Documentation related fields.
162      */
163     DOC doc;
164 
165     /**
166      * @brief The callout JSON, if the entry has callouts.
167      */
168     std::optional<nlohmann::json> callouts;
169 };
170 
171 /**
172  * @class Registry
173  *
174  * This class wraps the message registry JSON data and allows one to find
175  * the message registry entry pertaining to the error name.
176  *
177  * So that new registry files can easily be tested, the code will look for
178  * /etc/phosphor-logging/message_registry.json before looking for the real
179  * path.
180  */
181 class Registry
182 {
183   public:
184     Registry() = delete;
185     ~Registry() = default;
186     Registry(const Registry&) = default;
187     Registry& operator=(const Registry&) = default;
188     Registry(Registry&&) = default;
189     Registry& operator=(Registry&&) = default;
190 
191     /**
192      * @brief Constructor
193      *
194      * Will load the callout JSON.
195      *
196      * @param[in] registryFile - The path to the file.
197      */
198     explicit Registry(const std::filesystem::path& registryFile) :
199         Registry(registryFile, true)
200     {
201     }
202 
203     /**
204      * @brief Constructor
205      *
206      * This version contains a parameter that allows the callout JSON
207      * to be saved in the Entry struct or not, as it isn't needed at
208      * all in some cases.
209      *
210      * @param[in] registryFile - The path to the file.
211      * @param[in] loadCallouts - If the callout JSON should be saved.
212      */
213     explicit Registry(const std::filesystem::path& registryFile,
214                       bool loadCallouts) :
215         _registryFile(registryFile),
216         _loadCallouts(loadCallouts)
217     {
218     }
219 
220     /**
221      * @brief Find a registry entry based on its error name or reason code.
222      *
223      * This function does do some basic sanity checking on the JSON contents,
224      * but there is also an external program that enforces a schema on the
225      * registry JSON that should catch all of these problems ahead of time.
226      *
227      * @param[in] name - The error name, like xyz.openbmc_project.Error.Foo
228      *                 - OR
229      *                 - The reason code, like 0x1001
230      * @param[in] type - LookupType enum value
231      * @param[in] toCache - boolean to cache registry in memory
232      * @return optional<Entry> A filled in message registry structure if
233      *                         found, otherwise an empty optional object.
234      */
235     std::optional<Entry> lookup(const std::string& name, LookupType type,
236                                 bool toCache = false);
237 
238   private:
239     /**
240      * @brief Parse message registry file using nlohmann::json
241      * @param[in] registryFile - The message registry JSON file
242      * @return optional<nlohmann::json> The full message registry object or an
243      *                                  empty optional object upon failure.
244      */
245     std::optional<nlohmann::json>
246         readRegistry(const std::filesystem::path& registryFile);
247 
248     /**
249      * @brief The path to the registry JSON file.
250      */
251     std::filesystem::path _registryFile;
252 
253     /**
254      * @brief The full message registry object.
255      */
256     std::optional<nlohmann::json> _registry;
257 
258     /**
259      * @brief If the callout JSON should be saved in the Entry on lookup.
260      */
261     bool _loadCallouts;
262 };
263 
264 namespace helper
265 {
266 
267 /**
268  * @brief A helper function to get the PEL subsystem value based on
269  *        the registry subsystem name.
270  *
271  * @param[in] subsystemName - The registry name for the subsystem
272  *
273  * @return uint8_t The PEL subsystem value
274  */
275 uint8_t getSubsystem(const std::string& subsystemName);
276 
277 /**
278  * @brief A helper function to get the PEL severity value based on
279  *        the registry severity name.
280  *
281  * @param[in] severityName - The registry name for the severity
282  *
283  * @return uint8_t The PEL severity value
284  */
285 uint8_t getSeverity(const std::string& severityName);
286 
287 /**
288  * @brief A helper function to get the action flags value based on
289  *        the action flag names used in the registry.
290  *
291  * @param[in] flags - The list of flag names from the registry.
292  *
293  * @return uint16_t - The bitfield of flags used in the PEL.
294  */
295 uint16_t getActionFlags(const std::vector<std::string>& flags);
296 
297 /**
298  * @brief A helper function to get the PEL event type value based on
299  *        the registry event type name.
300  *
301  * @param[in] eventTypeName - The registry name for the event type
302  *
303  * @return uint8_t The PEL event type value
304  */
305 uint8_t getEventType(const std::string& eventTypeName);
306 
307 /**
308  * @brief A helper function to get the PEL event scope value based on
309  *        the registry event scope name.
310  *
311  * @param[in] eventScopeName - The registry name for the event scope
312  *
313  * @return uint8_t The PEL event scope value
314  */
315 uint8_t getEventScope(const std::string& eventScopeName);
316 
317 /**
318  * @brief Reads the "ReasonCode" field out of JSON and converts the string value
319  *        such as "0x5555" to a uint16 like 0x5555.
320  *
321  * @param[in] src - The message registry SRC dictionary to read from
322  * @param[in] name - The error name, to use in a trace if things go awry.
323  *
324  * @return uint16_t - The reason code
325  */
326 uint16_t getSRCReasonCode(const nlohmann::json& src, const std::string& name);
327 
328 /**
329  * @brief Reads the "Type" field out of JSON and converts it to the SRC::Type
330  *        value.
331  *
332  * @param[in] src - The message registry SRC dictionary to read from
333  * @param[in] name - The error name, to use in a trace if things go awry.
334  *
335  * @return uint8_t - The SRC type value, like 0x11
336  */
337 uint8_t getSRCType(const nlohmann::json& src, const std::string& name);
338 
339 /**
340  * @brief Reads the "Words6To9" field out of JSON and converts it to a map
341  *        of the SRC word number to the AdditionalData property field used
342  *        to fill it in with.
343  *
344  * @param[in] src - The message registry SRC dictionary to read from
345  * @param[in] name - The error name, to use in a trace if things go awry.
346  *
347  * @return std::optional<std::map<SRC::WordNum, SRC::AdditionalDataField>>
348  */
349 std::optional<std::map<SRC::WordNum, SRC::AdditionalDataField>>
350     getSRCHexwordFields(const nlohmann::json& src, const std::string& name);
351 
352 /**
353  * @brief Reads the "SymptomIDFields" field out of JSON and converts it to
354  *        a vector of SRC word numbers.
355  *
356  * @param[in] src - The message registry SRC dictionary to read from
357  * @param[in] name - The error name, to use in a trace if things go awry.
358  *
359  * @return std::optional<std::vector<SRC::WordNum>>
360  */
361 std::optional<std::vector<SRC::WordNum>>
362     getSRCSymptomIDFields(const nlohmann::json& src, const std::string& name);
363 
364 /**
365  * @brief Reads the "ComponentID" field out of JSON and converts it to a
366  *        uint16_t like 0xFF00.
367  *
368  * The ComponentID JSON field is only required if the SRC type isn't a BD
369  * BMC SRC, because for those SRCs it can be inferred from the upper byte
370  * of the SRC reasoncode.
371  *
372  * @param[in] srcType - The SRC type
373  * @param[in] reasonCode - The SRC reason code
374  * @param[in] pelEntry - The PEL entry JSON
375  * @param[in] name - The error name, to use in a trace if things go awry.
376  *
377  * @return uin16_t - The component ID, like 0xFF00
378  */
379 uint16_t getComponentID(uint8_t srcType, uint16_t reasonCode,
380                         const nlohmann::json& pelEntry,
381                         const std::string& name);
382 
383 } // namespace helper
384 
385 } // namespace message
386 
387 } // namespace pels
388 } // namespace openpower
389