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