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 17 /** 18 * @brief Represents the SRC related fields in the message registry. 19 * It is part of the 'Entry' structure that will be filled in when 20 * an error is looked up in the registry. 21 * 22 * If a field is wrapped by std::optional, it means the field is 23 * optional in the JSON and higher level code knows how to handle it. 24 */ 25 struct SRC 26 { 27 /** 28 * @brief SRC type - The first byte of the ASCII string 29 */ 30 uint8_t type; 31 32 /** 33 * @brief The SRC reason code (2nd half of 4B 'ASCII string' word) 34 */ 35 uint16_t reasonCode; 36 37 /** 38 * @brief Specifies if the SRC represents a power fault. Optional. 39 */ 40 std::optional<bool> powerFault; 41 42 /** 43 * @brief An optional vector of SRC hexword numbers that should be used 44 * along with the SRC ASCII string to build the Symptom ID, which 45 * is a field in the Extended Header section. 46 */ 47 using WordNum = size_t; 48 std::optional<std::vector<WordNum>> symptomID; 49 50 /** 51 * @brief Which AdditionalData fields to use to fill in the user defined 52 * SRC hexwords. 53 * 54 * For example, if the AdditionalData event log property contained 55 * "CHIPNUM=42" and this map contained {6, CHIPNUM}, then the code 56 * would put 42 into SRC hexword 6. 57 */ 58 using AdditionalDataField = std::string; 59 std::optional<std::map<WordNum, AdditionalDataField>> hexwordADFields; 60 61 SRC() : type(0), reasonCode(0) 62 { 63 } 64 }; 65 66 /** 67 * @brief Represents a message registry entry, which is used for creating a 68 * PEL from an OpenBMC event log. 69 */ 70 struct Entry 71 { 72 /** 73 * @brief The error name, like "xyz.openbmc_project.Error.Foo". 74 */ 75 std::string name; 76 77 /** 78 * @brief The component ID of the PEL creator. 79 */ 80 uint16_t componentID; 81 82 /** 83 * @brief The PEL subsystem field. 84 */ 85 uint8_t subsystem; 86 87 /** 88 * @brief The optional PEL severity field. If not specified, the PEL 89 * will use the severity of the OpenBMC event log. 90 */ 91 std::optional<uint8_t> severity; 92 93 /** 94 * @brief The optional severity field to use when in manufacturing tolerance 95 * mode. 96 */ 97 std::optional<uint8_t> mfgSeverity; 98 99 /** 100 * @brief The PEL action flags field. 101 */ 102 uint16_t actionFlags; 103 104 /** 105 * @brief The optional action flags to use instead when in manufacturing 106 * tolerance mode. 107 */ 108 std::optional<uint16_t> mfgActionFlags; 109 110 /** 111 * @brief The PEL event type field. If not specified, higher level code 112 * will decide the value. 113 */ 114 std::optional<uint8_t> eventType; 115 116 /** 117 * @brief The PEL event scope field. If not specified, higher level code 118 * will decide the value. 119 */ 120 std::optional<uint8_t> eventScope; 121 122 /** 123 * The SRC related fields. 124 */ 125 SRC src; 126 }; 127 128 /** 129 * @class Registry 130 * 131 * This class wraps the message registry JSON data and allows one to find 132 * the message registry entry pertaining to the error name. 133 * 134 * So that new registry files can easily be tested, the code will look for 135 * /etc/phosphor-logging/message_registry.json before looking for the real 136 * path. 137 */ 138 class Registry 139 { 140 public: 141 Registry() = delete; 142 ~Registry() = default; 143 Registry(const Registry&) = default; 144 Registry& operator=(const Registry&) = default; 145 Registry(Registry&&) = default; 146 Registry& operator=(Registry&&) = default; 147 148 /** 149 * @brief Constructor 150 * @param[in] registryFile - The path to the file. 151 */ 152 explicit Registry(const std::filesystem::path& registryFile) : 153 _registryFile(registryFile) 154 { 155 } 156 157 /** 158 * @brief Find a registry entry based on its error name. 159 * 160 * This function does do some basic sanity checking on the JSON contents, 161 * but there is also an external program that enforces a schema on the 162 * registry JSON that should catch all of these problems ahead of time. 163 * 164 * @param[in] name - The error name, like xyz.openbmc_project.Error.Foo 165 * 166 * @return optional<Entry> A filled in message registry structure if 167 * found, otherwise an empty optional object. 168 */ 169 std::optional<Entry> lookup(const std::string& name); 170 171 private: 172 /** 173 * @brief The path to the registry JSON file. 174 */ 175 std::filesystem::path _registryFile; 176 }; 177 178 namespace helper 179 { 180 181 /** 182 * @brief A helper function to get the PEL subsystem value based on 183 * the registry subsystem name. 184 * 185 * @param[in] subsystemName - The registry name for the subsystem 186 * 187 * @return uint8_t The PEL subsystem value 188 */ 189 uint8_t getSubsystem(const std::string& subsystemName); 190 191 /** 192 * @brief A helper function to get the PEL severity value based on 193 * the registry severity name. 194 * 195 * @param[in] severityName - The registry name for the severity 196 * 197 * @return uint8_t The PEL severity value 198 */ 199 uint8_t getSeverity(const std::string& severityName); 200 201 /** 202 * @brief A helper function to get the action flags value based on 203 * the action flag names used in the registry. 204 * 205 * @param[in] flags - The list of flag names from the registry. 206 * 207 * @return uint16_t - The bitfield of flags used in the PEL. 208 */ 209 uint16_t getActionFlags(const std::vector<std::string>& flags); 210 211 /** 212 * @brief A helper function to get the PEL event type value based on 213 * the registry event type name. 214 * 215 * @param[in] eventTypeName - The registry name for the event type 216 * 217 * @return uint8_t The PEL event type value 218 */ 219 uint8_t getEventType(const std::string& eventTypeName); 220 221 /** 222 * @brief A helper function to get the PEL event scope value based on 223 * the registry event scope name. 224 * 225 * @param[in] eventScopeName - The registry name for the event scope 226 * 227 * @return uint8_t The PEL event scope value 228 */ 229 uint8_t getEventScope(const std::string& eventScopeName); 230 231 /** 232 * @brief Reads the "ReasonCode" field out of JSON and converts the string value 233 * such as "0x5555" to a uint16 like 0x5555. 234 * 235 * @param[in] src - The message registry SRC dictionary to read from 236 * @param[in] name - The error name, to use in a trace if things go awry. 237 * 238 * @return uint16_t - The reason code 239 */ 240 uint16_t getSRCReasonCode(const nlohmann::json& src, const std::string& name); 241 242 /** 243 * @brief Reads the "Type" field out of JSON and converts it to the SRC::Type 244 * value. 245 * 246 * @param[in] src - The message registry SRC dictionary to read from 247 * @param[in] name - The error name, to use in a trace if things go awry. 248 * 249 * @return uint8_t - The SRC type value, like 0x11 250 */ 251 uint8_t getSRCType(const nlohmann::json& src, const std::string& name); 252 253 /** 254 * @brief Reads the "Words6To9" field out of JSON and converts it to a map 255 * of the SRC word number to the AdditionalData property field used 256 * to fill it in with. 257 * 258 * @param[in] src - The message registry SRC dictionary to read from 259 * @param[in] name - The error name, to use in a trace if things go awry. 260 * 261 * @return std::optional<std::map<SRC::WordNum, SRC::AdditionalDataField>> 262 */ 263 std::optional<std::map<SRC::WordNum, SRC::AdditionalDataField>> 264 getSRCHexwordFields(const nlohmann::json& src, const std::string& name); 265 266 /** 267 * @brief Reads the "SymptomIDFields" field out of JSON and converts it to 268 * a vector of SRC word numbers. 269 * 270 * @param[in] src - The message registry SRC dictionary to read from 271 * @param[in] name - The error name, to use in a trace if things go awry. 272 * 273 * @return std::optional<std::vector<SRC::WordNum>> 274 */ 275 std::optional<std::vector<SRC::WordNum>> 276 getSRCSymptomIDFields(const nlohmann::json& src, const std::string& name); 277 278 /** 279 * @brief Reads the "ComponentID" field out of JSON and converts it to a 280 * uint16_t like 0xFF00. 281 * 282 * The ComponentID JSON field is only required if the SRC type isn't a BD 283 * BMC SRC, because for those SRCs it can be inferred from the upper byte 284 * of the SRC reasoncode. 285 * 286 * @param[in] srcType - The SRC type 287 * @param[in] reasonCode - The SRC reason code 288 * @param[in] pelEntry - The PEL entry JSON 289 * @param[in] name - The error name, to use in a trace if things go awry. 290 * 291 * @return uin16_t - The component ID, like 0xFF00 292 */ 293 uint16_t getComponentID(uint8_t srcType, uint16_t reasonCode, 294 const nlohmann::json& pelEntry, 295 const std::string& name); 296 297 } // namespace helper 298 299 } // namespace message 300 301 } // namespace pels 302 } // namespace openpower 303