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 /** 167 * @class Registry 168 * 169 * This class wraps the message registry JSON data and allows one to find 170 * the message registry entry pertaining to the error name. 171 * 172 * So that new registry files can easily be tested, the code will look for 173 * /etc/phosphor-logging/message_registry.json before looking for the real 174 * path. 175 */ 176 class Registry 177 { 178 public: 179 Registry() = delete; 180 ~Registry() = default; 181 Registry(const Registry&) = default; 182 Registry& operator=(const Registry&) = default; 183 Registry(Registry&&) = default; 184 Registry& operator=(Registry&&) = default; 185 186 /** 187 * @brief Constructor 188 * @param[in] registryFile - The path to the file. 189 */ 190 explicit Registry(const std::filesystem::path& registryFile) : 191 _registryFile(registryFile) 192 { 193 } 194 195 /** 196 * @brief Find a registry entry based on its error name or reason code. 197 * 198 * This function does do some basic sanity checking on the JSON contents, 199 * but there is also an external program that enforces a schema on the 200 * registry JSON that should catch all of these problems ahead of time. 201 * 202 * @param[in] name - The error name, like xyz.openbmc_project.Error.Foo 203 * - OR 204 * - The reason code, like 0x1001 205 * @param[in] type - LookupType enum value 206 * @param[in] toCache - boolean to cache registry in memory 207 * @return optional<Entry> A filled in message registry structure if 208 * found, otherwise an empty optional object. 209 */ 210 std::optional<Entry> lookup(const std::string& name, LookupType type, 211 bool toCache = false); 212 213 private: 214 /** 215 * @brief Parse message registry file using nlohmann::json 216 * @param[in] registryFile - The message registry JSON file 217 * @return optional<nlohmann::json> The full message registry object or an 218 * empty optional object upon failure. 219 */ 220 std::optional<nlohmann::json> 221 readRegistry(const std::filesystem::path& registryFile); 222 223 /** 224 * @brief The path to the registry JSON file. 225 */ 226 std::filesystem::path _registryFile; 227 228 /** 229 * @brief The full message registry object. 230 */ 231 std::optional<nlohmann::json> _registry; 232 }; 233 234 namespace helper 235 { 236 237 /** 238 * @brief A helper function to get the PEL subsystem value based on 239 * the registry subsystem name. 240 * 241 * @param[in] subsystemName - The registry name for the subsystem 242 * 243 * @return uint8_t The PEL subsystem value 244 */ 245 uint8_t getSubsystem(const std::string& subsystemName); 246 247 /** 248 * @brief A helper function to get the PEL severity value based on 249 * the registry severity name. 250 * 251 * @param[in] severityName - The registry name for the severity 252 * 253 * @return uint8_t The PEL severity value 254 */ 255 uint8_t getSeverity(const std::string& severityName); 256 257 /** 258 * @brief A helper function to get the action flags value based on 259 * the action flag names used in the registry. 260 * 261 * @param[in] flags - The list of flag names from the registry. 262 * 263 * @return uint16_t - The bitfield of flags used in the PEL. 264 */ 265 uint16_t getActionFlags(const std::vector<std::string>& flags); 266 267 /** 268 * @brief A helper function to get the PEL event type value based on 269 * the registry event type name. 270 * 271 * @param[in] eventTypeName - The registry name for the event type 272 * 273 * @return uint8_t The PEL event type value 274 */ 275 uint8_t getEventType(const std::string& eventTypeName); 276 277 /** 278 * @brief A helper function to get the PEL event scope value based on 279 * the registry event scope name. 280 * 281 * @param[in] eventScopeName - The registry name for the event scope 282 * 283 * @return uint8_t The PEL event scope value 284 */ 285 uint8_t getEventScope(const std::string& eventScopeName); 286 287 /** 288 * @brief Reads the "ReasonCode" field out of JSON and converts the string value 289 * such as "0x5555" to a uint16 like 0x5555. 290 * 291 * @param[in] src - The message registry SRC dictionary to read from 292 * @param[in] name - The error name, to use in a trace if things go awry. 293 * 294 * @return uint16_t - The reason code 295 */ 296 uint16_t getSRCReasonCode(const nlohmann::json& src, const std::string& name); 297 298 /** 299 * @brief Reads the "Type" field out of JSON and converts it to the SRC::Type 300 * value. 301 * 302 * @param[in] src - The message registry SRC dictionary to read from 303 * @param[in] name - The error name, to use in a trace if things go awry. 304 * 305 * @return uint8_t - The SRC type value, like 0x11 306 */ 307 uint8_t getSRCType(const nlohmann::json& src, const std::string& name); 308 309 /** 310 * @brief Reads the "Words6To9" field out of JSON and converts it to a map 311 * of the SRC word number to the AdditionalData property field used 312 * to fill it in with. 313 * 314 * @param[in] src - The message registry SRC dictionary to read from 315 * @param[in] name - The error name, to use in a trace if things go awry. 316 * 317 * @return std::optional<std::map<SRC::WordNum, SRC::AdditionalDataField>> 318 */ 319 std::optional<std::map<SRC::WordNum, SRC::AdditionalDataField>> 320 getSRCHexwordFields(const nlohmann::json& src, const std::string& name); 321 322 /** 323 * @brief Reads the "SymptomIDFields" field out of JSON and converts it to 324 * a vector of SRC word numbers. 325 * 326 * @param[in] src - The message registry SRC dictionary to read from 327 * @param[in] name - The error name, to use in a trace if things go awry. 328 * 329 * @return std::optional<std::vector<SRC::WordNum>> 330 */ 331 std::optional<std::vector<SRC::WordNum>> 332 getSRCSymptomIDFields(const nlohmann::json& src, const std::string& name); 333 334 /** 335 * @brief Reads the "ComponentID" field out of JSON and converts it to a 336 * uint16_t like 0xFF00. 337 * 338 * The ComponentID JSON field is only required if the SRC type isn't a BD 339 * BMC SRC, because for those SRCs it can be inferred from the upper byte 340 * of the SRC reasoncode. 341 * 342 * @param[in] srcType - The SRC type 343 * @param[in] reasonCode - The SRC reason code 344 * @param[in] pelEntry - The PEL entry JSON 345 * @param[in] name - The error name, to use in a trace if things go awry. 346 * 347 * @return uin16_t - The component ID, like 0xFF00 348 */ 349 uint16_t getComponentID(uint8_t srcType, uint16_t reasonCode, 350 const nlohmann::json& pelEntry, 351 const std::string& name); 352 353 } // namespace helper 354 355 } // namespace message 356 357 } // namespace pels 358 } // namespace openpower 359