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