xref: /openbmc/phosphor-logging/extensions/openpower-pels/registry.hpp (revision e07f915b21c5915574d03f9c9b7527084da4abe6)
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 
17 /**
18  * @brief Represents the SRC related fields in the message registry.
19  *        It is part of the 'Entry' structure that will be filled in when
20  *        an error is looked up in the registry.
21  *
22  * If a field is wrapped by std::optional, it means the field is
23  * optional in the JSON and higher level code knows how to handle it.
24  */
25 struct SRC
26 {
27     /**
28      * @brief SRC type - The first byte of the ASCII string
29      */
30     uint8_t type;
31 
32     /**
33      * @brief The SRC reason code (2nd half of 4B 'ASCII string' word)
34      */
35     uint16_t reasonCode;
36 
37     /**
38      * @brief Specifies if the SRC represents a power fault.  Optional.
39      */
40     std::optional<bool> powerFault;
41 
42     /**
43      * @brief An optional vector of SRC hexword numbers that should be used
44      *        along with the SRC ASCII string to build the Symptom ID, which
45      *        is a field in the Extended Header section.
46      */
47     using WordNum = size_t;
48     std::optional<std::vector<WordNum>> symptomID;
49 
50     /**
51      * @brief Which AdditionalData fields to use to fill in the user defined
52      *        SRC hexwords.
53      *
54      * For example, if the AdditionalData event log property contained
55      * "CHIPNUM=42" and this map contained {6, CHIPNUM}, then the code
56      * would put 42 into SRC hexword 6.
57      */
58     using AdditionalDataField = std::string;
59     std::optional<std::map<WordNum, AdditionalDataField>> hexwordADFields;
60 
61     SRC() : type(0), reasonCode(0)
62     {
63     }
64 };
65 
66 /**
67  * @brief Represents a message registry entry, which is used for creating a
68  *        PEL from an OpenBMC event log.
69  */
70 struct Entry
71 {
72     /**
73      * @brief The error name, like "xyz.openbmc_project.Error.Foo".
74      */
75     std::string name;
76 
77     /**
78      * @brief The component ID of the PEL creator.
79      */
80     uint16_t componentID;
81 
82     /**
83      * @brief The PEL subsystem field.
84      */
85     uint8_t subsystem;
86 
87     /**
88      * @brief The optional PEL severity field.  If not specified, the PEL
89      *        will use the severity of the OpenBMC event log.
90      */
91     std::optional<uint8_t> severity;
92 
93     /**
94      * @brief The optional severity field to use when in manufacturing tolerance
95      *        mode.
96      */
97     std::optional<uint8_t> mfgSeverity;
98 
99     /**
100      * @brief The PEL action flags field.
101      */
102     std::optional<uint16_t> actionFlags;
103 
104     /**
105      * @brief  The optional action flags to use instead when in manufacturing
106      * tolerance mode.
107      */
108     std::optional<uint16_t> mfgActionFlags;
109 
110     /**
111      * @brief The PEL event type field.  If not specified, higher level code
112      *        will decide the value.
113      */
114     std::optional<uint8_t> eventType;
115 
116     /**
117      * @brief The PEL event scope field.  If not specified, higher level code
118      *        will decide the value.
119      */
120     std::optional<uint8_t> eventScope;
121 
122     /**
123      * The SRC related fields.
124      */
125     SRC src;
126 };
127 
128 /**
129  * @class Registry
130  *
131  * This class wraps the message registry JSON data and allows one to find
132  * the message registry entry pertaining to the error name.
133  *
134  * So that new registry files can easily be tested, the code will look for
135  * /etc/phosphor-logging/message_registry.json before looking for the real
136  * path.
137  */
138 class Registry
139 {
140   public:
141     Registry() = delete;
142     ~Registry() = default;
143     Registry(const Registry&) = default;
144     Registry& operator=(const Registry&) = default;
145     Registry(Registry&&) = default;
146     Registry& operator=(Registry&&) = default;
147 
148     /**
149      * @brief Constructor
150      * @param[in] registryFile - The path to the file.
151      */
152     explicit Registry(const std::filesystem::path& registryFile) :
153         _registryFile(registryFile)
154     {
155     }
156 
157     /**
158      * @brief Find a registry entry based on its error name.
159      *
160      * This function does do some basic sanity checking on the JSON contents,
161      * but there is also an external program that enforces a schema on the
162      * registry JSON that should catch all of these problems ahead of time.
163      *
164      * @param[in] name - The error name, like xyz.openbmc_project.Error.Foo
165      *
166      * @return optional<Entry> A filled in message registry structure if
167      *                         found, otherwise an empty optional object.
168      */
169     std::optional<Entry> lookup(const std::string& name);
170 
171   private:
172     /**
173      * @brief The path to the registry JSON file.
174      */
175     std::filesystem::path _registryFile;
176 };
177 
178 namespace helper
179 {
180 
181 /**
182  * @brief A helper function to get the PEL subsystem value based on
183  *        the registry subsystem name.
184  *
185  * @param[in] subsystemName - The registry name for the subsystem
186  *
187  * @return uint8_t The PEL subsystem value
188  */
189 uint8_t getSubsystem(const std::string& subsystemName);
190 
191 /**
192  * @brief A helper function to get the PEL severity value based on
193  *        the registry severity name.
194  *
195  * @param[in] severityName - The registry name for the severity
196  *
197  * @return uint8_t The PEL severity value
198  */
199 uint8_t getSeverity(const std::string& severityName);
200 
201 /**
202  * @brief A helper function to get the action flags value based on
203  *        the action flag names used in the registry.
204  *
205  * @param[in] flags - The list of flag names from the registry.
206  *
207  * @return uint16_t - The bitfield of flags used in the PEL.
208  */
209 uint16_t getActionFlags(const std::vector<std::string>& flags);
210 
211 /**
212  * @brief A helper function to get the PEL event type value based on
213  *        the registry event type name.
214  *
215  * @param[in] eventTypeName - The registry name for the event type
216  *
217  * @return uint8_t The PEL event type value
218  */
219 uint8_t getEventType(const std::string& eventTypeName);
220 
221 /**
222  * @brief A helper function to get the PEL event scope value based on
223  *        the registry event scope name.
224  *
225  * @param[in] eventScopeName - The registry name for the event scope
226  *
227  * @return uint8_t The PEL event scope value
228  */
229 uint8_t getEventScope(const std::string& eventScopeName);
230 
231 /**
232  * @brief Reads the "ReasonCode" field out of JSON and converts the string value
233  *        such as "0x5555" to a uint16 like 0x5555.
234  *
235  * @param[in] src - The message registry SRC dictionary to read from
236  * @param[in] name - The error name, to use in a trace if things go awry.
237  *
238  * @return uint16_t - The reason code
239  */
240 uint16_t getSRCReasonCode(const nlohmann::json& src, const std::string& name);
241 
242 /**
243  * @brief Reads the "Type" field out of JSON and converts it to the SRC::Type
244  *        value.
245  *
246  * @param[in] src - The message registry SRC dictionary to read from
247  * @param[in] name - The error name, to use in a trace if things go awry.
248  *
249  * @return uint8_t - The SRC type value, like 0x11
250  */
251 uint8_t getSRCType(const nlohmann::json& src, const std::string& name);
252 
253 /**
254  * @brief Reads the "Words6To9" field out of JSON and converts it to a map
255  *        of the SRC word number to the AdditionalData property field used
256  *        to fill it in with.
257  *
258  * @param[in] src - The message registry SRC dictionary to read from
259  * @param[in] name - The error name, to use in a trace if things go awry.
260  *
261  * @return std::optional<std::map<SRC::WordNum, SRC::AdditionalDataField>>
262  */
263 std::optional<std::map<SRC::WordNum, SRC::AdditionalDataField>>
264     getSRCHexwordFields(const nlohmann::json& src, const std::string& name);
265 
266 /**
267  * @brief Reads the "SymptomIDFields" field out of JSON and converts it to
268  *        a vector of SRC word numbers.
269  *
270  * @param[in] src - The message registry SRC dictionary to read from
271  * @param[in] name - The error name, to use in a trace if things go awry.
272  *
273  * @return std::optional<std::vector<SRC::WordNum>>
274  */
275 std::optional<std::vector<SRC::WordNum>>
276     getSRCSymptomIDFields(const nlohmann::json& src, const std::string& name);
277 
278 /**
279  * @brief Reads the "ComponentID" field out of JSON and converts it to a
280  *        uint16_t like 0xFF00.
281  *
282  * The ComponentID JSON field is only required if the SRC type isn't a BD
283  * BMC SRC, because for those SRCs it can be inferred from the upper byte
284  * of the SRC reasoncode.
285  *
286  * @param[in] srcType - The SRC type
287  * @param[in] reasonCode - The SRC reason code
288  * @param[in] pelEntry - The PEL entry JSON
289  * @param[in] name - The error name, to use in a trace if things go awry.
290  *
291  * @return uin16_t - The component ID, like 0xFF00
292  */
293 uint16_t getComponentID(uint8_t srcType, uint16_t reasonCode,
294                         const nlohmann::json& pelEntry,
295                         const std::string& name);
296 
297 } // namespace helper
298 
299 } // namespace message
300 
301 } // namespace pels
302 } // namespace openpower
303