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