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