#pragma once #include "additional_data.hpp" #include #include #include #include #include #include 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> messageArgSources; }; /** * @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> 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::optional> hexwordADFields; /** * @brief If the Deconfigured flag should be set in hex word 5 */ bool deconfigFlag; /** * @brief If the checkstop flag should be set in hex word 5 */ bool checkstopFlag; SRC() : type(0), reasonCode(0), deconfigFlag(false), checkstopFlag(false) {} }; struct AppCapture { std::string syslogID; size_t numLines; }; // Can specify either the syslog IDs to capture along with how many // entries of each, or just how many entries to get the full journal. using AppCaptureList = std::vector; using JournalCapture = std::variant; /** * @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 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> severity; /** * @brief The optional severity field to use when in manufacturing tolerance * mode. It behaves like the severity field above. */ std::optional> mfgSeverity; /** * @brief The PEL action flags field. */ std::optional actionFlags; /** * @brief The optional action flags to use instead when in manufacturing * tolerance mode. */ std::optional mfgActionFlags; /** * @brief The PEL event type field. If not specified, higher level code * will decide the value. */ std::optional eventType; /** * @brief The PEL event scope field. If not specified, higher level code * will decide the value. */ std::optional eventScope; /** * The SRC related fields. */ SRC src; /** * The Documentation related fields. */ DOC doc; /** * @brief The callout JSON, if the entry has callouts. */ std::optional callouts; /** * @brief The journal capture instructions, if present. */ std::optional journalCapture; }; /** * @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 A filled in message registry structure if * found, otherwise an empty optional object. */ std::optional 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 - The callouts to use */ static std::vector getCallouts(const nlohmann::json& calloutJSON, const std::vector& systemNames, const AdditionalData& additionalData); private: /** * @brief Parse message registry file using nlohmann::json * @param[in] registryFile - The message registry JSON file * @return optional The full message registry object or an * empty optional object upon failure. */ std::optional 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 _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 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& 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::optional> 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::optional> getSRCSymptomIDFields(const nlohmann::json& src, const std::string& name); /** * @brief Returns the value of the 'DeconfigFlag' field. * * @param[in] src - The message registry SRC dictionary to read from * * @return bool - The field value */ bool getSRCDeconfigFlag(const nlohmann::json& src); /** * @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