| #pragma once |
| #include "additional_data.hpp" |
| |
| #include <filesystem> |
| #include <nlohmann/json.hpp> |
| #include <optional> |
| #include <string> |
| #include <vector> |
| |
| namespace openpower |
| { |
| namespace pels |
| { |
| namespace message |
| { |
| |
| constexpr auto registryFileName = "message_registry.json"; |
| enum class LookupType |
| { |
| name = 0, |
| reasonCode = 1 |
| }; |
| |
| /** |
| * @brief A possible severity/system type combination |
| * |
| * If there is no system type defined for this entry, |
| * then the system field will be empty. |
| */ |
| struct RegistrySeverity |
| { |
| std::string system; |
| uint8_t severity; |
| }; |
| |
| /** |
| * @brief Represents the Documentation related fields in the message registry. |
| * It is part of the 'Entry' structure that will be filled in when |
| * an error is looked up in the registry. |
| * |
| * If a field is wrapped by std::optional, it means the field is |
| * optional in the JSON and higher level code knows how to handle it. |
| */ |
| struct DOC |
| { |
| /** |
| * @brief Description of error |
| */ |
| std::string description; |
| |
| /** |
| * @brief Error message field |
| */ |
| std::string message; |
| |
| /** |
| * @brief An optional vector of SRC word 6-9 to use as the source of the |
| * numeric arguments that will be substituted into any placeholder |
| * in the Message field. |
| */ |
| std::optional<std::vector<std::string>> messageArgSources; |
| |
| /** |
| * @brief An optional vector of string that forms the Notes field. |
| */ |
| std::optional<std::vector<std::string>> notes; |
| }; |
| |
| /** |
| * @brief Represents the SRC related fields in the message registry. |
| * It is part of the 'Entry' structure that will be filled in when |
| * an error is looked up in the registry. |
| * |
| * If a field is wrapped by std::optional, it means the field is |
| * optional in the JSON and higher level code knows how to handle it. |
| */ |
| struct SRC |
| { |
| /** |
| * @brief SRC type - The first byte of the ASCII string |
| */ |
| uint8_t type; |
| |
| /** |
| * @brief The SRC reason code (2nd half of 4B 'ASCII string' word) |
| */ |
| uint16_t reasonCode; |
| |
| /** |
| * @brief An optional vector of SRC hexword numbers that should be used |
| * along with the SRC ASCII string to build the Symptom ID, which |
| * is a field in the Extended Header section. |
| */ |
| using WordNum = size_t; |
| std::optional<std::vector<WordNum>> symptomID; |
| |
| /** |
| * @brief Which AdditionalData fields to use to fill in the user defined |
| * SRC hexwords. |
| * |
| * For example, if the AdditionalData event log property contained |
| * "CHIPNUM=42" and this map contained {6, {"CHIPNUM", "DESC"}}, then the |
| * code would put 42 into SRC hexword 6. |
| * |
| * AdditionalDataField specifies two fields from the SRC entry in the |
| * message registry: "AdditionalDataPropSource" and "Description" |
| */ |
| using AdditionalDataField = std::tuple<std::string, std::string>; |
| std::optional<std::map<WordNum, AdditionalDataField>> hexwordADFields; |
| |
| SRC() : type(0), reasonCode(0) |
| { |
| } |
| }; |
| |
| /** |
| * @brief Represents a message registry entry, which is used for creating a |
| * PEL from an OpenBMC event log. |
| */ |
| struct Entry |
| { |
| /** |
| * @brief The error name, like "xyz.openbmc_project.Error.Foo". |
| */ |
| std::string name; |
| |
| /** |
| * @brief The component ID of the PEL creator. |
| */ |
| uint16_t componentID; |
| |
| /** |
| * @brief The PEL subsystem field. |
| */ |
| std::optional<uint8_t> subsystem; |
| |
| /** |
| * @brief The optional PEL severity field. If not specified, the PEL |
| * will use the severity of the OpenBMC event log. |
| * |
| * If the system type is specified in any of the entries in the vector, |
| * then the system type will be needed to find the actual severity. |
| */ |
| std::optional<std::vector<RegistrySeverity>> severity; |
| |
| /** |
| * @brief The optional severity field to use when in manufacturing tolerance |
| * mode. It behaves like the severity field above. |
| */ |
| std::optional<std::vector<RegistrySeverity>> mfgSeverity; |
| |
| /** |
| * @brief The PEL action flags field. |
| */ |
| std::optional<uint16_t> actionFlags; |
| |
| /** |
| * @brief The optional action flags to use instead when in manufacturing |
| * tolerance mode. |
| */ |
| std::optional<uint16_t> mfgActionFlags; |
| |
| /** |
| * @brief The PEL event type field. If not specified, higher level code |
| * will decide the value. |
| */ |
| std::optional<uint8_t> eventType; |
| |
| /** |
| * @brief The PEL event scope field. If not specified, higher level code |
| * will decide the value. |
| */ |
| std::optional<uint8_t> eventScope; |
| |
| /** |
| * The SRC related fields. |
| */ |
| SRC src; |
| |
| /** |
| * The Documentation related fields. |
| */ |
| DOC doc; |
| |
| /** |
| * @brief The callout JSON, if the entry has callouts. |
| */ |
| std::optional<nlohmann::json> callouts; |
| }; |
| |
| /** |
| * @brief Holds callout information pulled out of the JSON. |
| */ |
| struct RegistryCallout |
| { |
| std::string priority; |
| std::string locCode; |
| std::string procedure; |
| std::string symbolicFRU; |
| std::string symbolicFRUTrusted; |
| bool useInventoryLocCode; |
| }; |
| |
| /** |
| * @class Registry |
| * |
| * This class wraps the message registry JSON data and allows one to find |
| * the message registry entry pertaining to the error name. |
| * |
| * So that new registry files can easily be tested, the code will look for |
| * /etc/phosphor-logging/message_registry.json before looking for the real |
| * path. |
| */ |
| class Registry |
| { |
| public: |
| Registry() = delete; |
| ~Registry() = default; |
| Registry(const Registry&) = default; |
| Registry& operator=(const Registry&) = default; |
| Registry(Registry&&) = default; |
| Registry& operator=(Registry&&) = default; |
| |
| /** |
| * @brief Constructor |
| * |
| * Will load the callout JSON. |
| * |
| * @param[in] registryFile - The path to the file. |
| */ |
| explicit Registry(const std::filesystem::path& registryFile) : |
| Registry(registryFile, true) |
| { |
| } |
| |
| /** |
| * @brief Constructor |
| * |
| * This version contains a parameter that allows the callout JSON |
| * to be saved in the Entry struct or not, as it isn't needed at |
| * all in some cases. |
| * |
| * @param[in] registryFile - The path to the file. |
| * @param[in] loadCallouts - If the callout JSON should be saved. |
| */ |
| explicit Registry(const std::filesystem::path& registryFile, |
| bool loadCallouts) : |
| _registryFile(registryFile), |
| _loadCallouts(loadCallouts) |
| { |
| } |
| |
| /** |
| * @brief Find a registry entry based on its error name or reason code. |
| * |
| * This function does do some basic sanity checking on the JSON contents, |
| * but there is also an external program that enforces a schema on the |
| * registry JSON that should catch all of these problems ahead of time. |
| * |
| * @param[in] name - The error name, like xyz.openbmc_project.Error.Foo |
| * - OR |
| * - The reason code, like 0x1001 |
| * @param[in] type - LookupType enum value |
| * @param[in] toCache - boolean to cache registry in memory |
| * @return optional<Entry> A filled in message registry structure if |
| * found, otherwise an empty optional object. |
| */ |
| std::optional<Entry> lookup(const std::string& name, LookupType type, |
| bool toCache = false); |
| |
| /** |
| * @brief Find the callouts to put into the PEL based on the calloutJSON |
| * data. |
| * |
| * The system type and AdditionalData are used to index into the correct |
| * callout table. |
| * |
| * Throws exceptions on failures. |
| * |
| * @param[in] calloutJSON - Where to look up the callouts |
| * @param[in] systemNames - List of compatible system type names |
| * @param[in] additionalData - The AdditionalData property |
| * |
| * @return std::vector<RegistryCallout> - The callouts to use |
| */ |
| static std::vector<RegistryCallout> |
| getCallouts(const nlohmann::json& calloutJSON, |
| const std::vector<std::string>& systemNames, |
| const AdditionalData& additionalData); |
| |
| private: |
| /** |
| * @brief Parse message registry file using nlohmann::json |
| * @param[in] registryFile - The message registry JSON file |
| * @return optional<nlohmann::json> The full message registry object or an |
| * empty optional object upon failure. |
| */ |
| std::optional<nlohmann::json> |
| readRegistry(const std::filesystem::path& registryFile); |
| |
| /** |
| * @brief The path to the registry JSON file. |
| */ |
| std::filesystem::path _registryFile; |
| |
| /** |
| * @brief The full message registry object. |
| */ |
| std::optional<nlohmann::json> _registry; |
| |
| /** |
| * @brief If the callout JSON should be saved in the Entry on lookup. |
| */ |
| bool _loadCallouts; |
| }; |
| |
| namespace helper |
| { |
| |
| /** |
| * @brief A helper function to get the PEL subsystem value based on |
| * the registry subsystem name. |
| * |
| * @param[in] subsystemName - The registry name for the subsystem |
| * |
| * @return uint8_t The PEL subsystem value |
| */ |
| uint8_t getSubsystem(const std::string& subsystemName); |
| |
| /** |
| * @brief A helper function to get the PEL severity value based on |
| * the registry severity name. |
| * |
| * @param[in] severityName - The registry name for the severity |
| * |
| * @return uint8_t The PEL severity value |
| */ |
| uint8_t getSeverity(const std::string& severityName); |
| |
| /** |
| * @brief Returns all of the system type/severity values found |
| * in the severity JSON passed in. |
| * |
| * The JSON is either a simple string, like: |
| * "unrecoverable" |
| * or an array of system type/severity pairs, like: |
| * [ |
| * { |
| * "System": "1", |
| * "SevValue": "predictive" |
| * }, |
| * { |
| * "System": "2", |
| * "SevValue": "recovered" |
| * } |
| * ] |
| * |
| * @param[in] severity - The severity JSON |
| * @return The list of severity/system combinations. If the System key |
| * wasn't used, then that field will be empty in the structure. |
| */ |
| std::vector<RegistrySeverity> getSeverities(const nlohmann::json& severity); |
| |
| /** |
| * @brief A helper function to get the action flags value based on |
| * the action flag names used in the registry. |
| * |
| * @param[in] flags - The list of flag names from the registry. |
| * |
| * @return uint16_t - The bitfield of flags used in the PEL. |
| */ |
| uint16_t getActionFlags(const std::vector<std::string>& flags); |
| |
| /** |
| * @brief A helper function to get the PEL event type value based on |
| * the registry event type name. |
| * |
| * @param[in] eventTypeName - The registry name for the event type |
| * |
| * @return uint8_t The PEL event type value |
| */ |
| uint8_t getEventType(const std::string& eventTypeName); |
| |
| /** |
| * @brief A helper function to get the PEL event scope value based on |
| * the registry event scope name. |
| * |
| * @param[in] eventScopeName - The registry name for the event scope |
| * |
| * @return uint8_t The PEL event scope value |
| */ |
| uint8_t getEventScope(const std::string& eventScopeName); |
| |
| /** |
| * @brief Reads the "ReasonCode" field out of JSON and converts the string value |
| * such as "0x5555" to a uint16 like 0x5555. |
| * |
| * @param[in] src - The message registry SRC dictionary to read from |
| * @param[in] name - The error name, to use in a trace if things go awry. |
| * |
| * @return uint16_t - The reason code |
| */ |
| uint16_t getSRCReasonCode(const nlohmann::json& src, const std::string& name); |
| |
| /** |
| * @brief Reads the "Type" field out of JSON and converts it to the SRC::Type |
| * value. |
| * |
| * @param[in] src - The message registry SRC dictionary to read from |
| * @param[in] name - The error name, to use in a trace if things go awry. |
| * |
| * @return uint8_t - The SRC type value, like 0x11 |
| */ |
| uint8_t getSRCType(const nlohmann::json& src, const std::string& name); |
| |
| /** |
| * @brief Reads the "Words6To9" field out of JSON and converts it to a map |
| * of the SRC word number to the AdditionalData property field used |
| * to fill it in with. |
| * |
| * @param[in] src - The message registry SRC dictionary to read from |
| * @param[in] name - The error name, to use in a trace if things go awry. |
| * |
| * @return std::optional<std::map<SRC::WordNum, SRC::AdditionalDataField>> |
| */ |
| std::optional<std::map<SRC::WordNum, SRC::AdditionalDataField>> |
| getSRCHexwordFields(const nlohmann::json& src, const std::string& name); |
| |
| /** |
| * @brief Reads the "SymptomIDFields" field out of JSON and converts it to |
| * a vector of SRC word numbers. |
| * |
| * @param[in] src - The message registry SRC dictionary to read from |
| * @param[in] name - The error name, to use in a trace if things go awry. |
| * |
| * @return std::optional<std::vector<SRC::WordNum>> |
| */ |
| std::optional<std::vector<SRC::WordNum>> |
| getSRCSymptomIDFields(const nlohmann::json& src, const std::string& name); |
| |
| /** |
| * @brief Reads the "ComponentID" field out of JSON and converts it to a |
| * uint16_t like 0xFF00. |
| * |
| * The ComponentID JSON field is only required if the SRC type isn't a BD |
| * BMC SRC, because for those SRCs it can be inferred from the upper byte |
| * of the SRC reasoncode. |
| * |
| * @param[in] srcType - The SRC type |
| * @param[in] reasonCode - The SRC reason code |
| * @param[in] pelEntry - The PEL entry JSON |
| * @param[in] name - The error name, to use in a trace if things go awry. |
| * |
| * @return uin16_t - The component ID, like 0xFF00 |
| */ |
| uint16_t getComponentID(uint8_t srcType, uint16_t reasonCode, |
| const nlohmann::json& pelEntry, |
| const std::string& name); |
| |
| } // namespace helper |
| |
| } // namespace message |
| |
| } // namespace pels |
| } // namespace openpower |