blob: 5363864dee708e52f0a14cb9e8ff4128e17ca9ce [file] [log] [blame]
#pragma once
#include "additional_data.hpp"
#include "ascii_string.hpp"
#include "callouts.hpp"
#include "data_interface.hpp"
#include "pel_types.hpp"
#include "registry.hpp"
#include "section.hpp"
#include "stream.hpp"
namespace openpower
{
namespace pels
{
constexpr uint8_t srcSectionVersion = 0x01;
constexpr uint8_t srcSectionSubtype = 0x01;
constexpr size_t numSRCHexDataWords = 8;
constexpr uint8_t srcVersion = 0x02;
constexpr uint8_t bmcSRCFormat = 0x55;
constexpr uint8_t primaryBMCPosition = 0x10;
constexpr size_t baseSRCSize = 72;
enum class DetailLevel
{
message = 0x01,
json = 0x02
};
/**
* @class SRC
*
* SRC stands for System Reference Code.
*
* This class represents the SRC sections in the PEL, of which there are 2:
* primary SRC and secondary SRC. These are the same structurally, the
* difference is that the primary SRC must be the 3rd section in the PEL if
* present and there is only one of them, and the secondary SRC sections are
* optional and there can be more than one (by definition, for there to be a
* secondary SRC, a primary SRC must also exist).
*
* This section consists of:
* - An 8B header (Has the version, flags, hexdata word count, and size fields)
* - 8 4B words of hex data
* - An ASCII character string
* - An optional subsection for Callouts
*/
class SRC : public Section
{
public:
enum HeaderFlags
{
additionalSections = 0x01,
powerFaultEvent = 0x02,
hypDumpInit = 0x04,
i5OSServiceEventBit = 0x10,
virtualProgressSRC = 0x80
};
/**
* @brief Enums for the error status bits in hex word 5
* of BMC SRCs.
*/
enum class ErrorStatusFlags
{
deconfigured = 0x02000000,
guarded = 0x01000000
};
SRC() = delete;
~SRC() = default;
SRC(const SRC&) = delete;
SRC& operator=(const SRC&) = delete;
SRC(SRC&&) = delete;
SRC& operator=(SRC&&) = delete;
/**
* @brief Constructor
*
* Fills in this class's data fields from the stream.
*
* @param[in] pel - the PEL data stream
*/
explicit SRC(Stream& pel);
/**
* @brief Constructor
*
* Creates the section with data from the PEL message registry entry for
* this error, along with the AdditionalData property contents from the
* corresponding event log.
*
* @param[in] regEntry - The message registry entry for this event log
* @param[in] additionalData - The AdditionalData properties in this event
* log
* @param[in] dataIface - The DataInterface object
*/
SRC(const message::Entry& regEntry, const AdditionalData& additionalData,
const DataInterfaceBase& dataIface) :
SRC(regEntry, additionalData, nlohmann::json{}, dataIface)
{
}
/**
* @brief Constructor
*
* Creates the section with data from the PEL message registry entry for
* this error, along with the AdditionalData property contents from the
* corresponding event log, and a JSON array of callouts to add.
*
* @param[in] regEntry - The message registry entry for this event log
* @param[in] additionalData - The AdditionalData properties in this event
* log
* @param[in] jsonCallouts - The array of JSON callouts, or an empty object.
* @param[in] dataIface - The DataInterface object
*/
SRC(const message::Entry& regEntry, const AdditionalData& additionalData,
const nlohmann::json& jsonCallouts, const DataInterfaceBase& dataIface);
/**
* @brief Flatten the section into the stream
*
* @param[in] stream - The stream to write to
*/
void flatten(Stream& stream) const override;
/**
* @brief Returns the SRC version, which is a different field
* than the version byte in the section header.
*
* @return uint8_t
*/
uint8_t version() const
{
return _version;
}
/**
* @brief Returns the flags byte
*
* @return uint8_t
*/
uint8_t flags() const
{
return _flags;
}
/**
* @brief Returns the hex data word count.
*
* Even though there always 8 words, this returns 9 due to previous
* SRC version formats.
*
* @return uint8_t
*/
uint8_t hexWordCount() const
{
return _wordCount;
}
/**
* @brief Returns the size of the SRC section, not including the header.
*
* @return uint16_t
*/
uint16_t size() const
{
return _size;
}
/**
* @brief Returns the 8 hex data words.
*
* @return const std::array<uint32_t, numSRCHexDataWords>&
*/
const std::array<uint32_t, numSRCHexDataWords>& hexwordData() const
{
return _hexData;
}
/**
* @brief Returns the ASCII string
*
* @return std::string
*/
std::string asciiString() const
{
return _asciiString->get();
}
/**
* @brief Returns the callouts subsection
*
* If no callouts, this unique_ptr will be empty
*
* @return const std::unique_ptr<src::Callouts>&
*/
const std::unique_ptr<src::Callouts>& callouts() const
{
return _callouts;
}
/**
* @brief Returns the size of this section when flattened into a PEL
*
* @return size_t - the size of the section
*/
size_t flattenedSize() const
{
return _header.size;
}
/**
* @brief Says if this SRC has additional subsections in it
*
* Note: The callouts section is the only possible subsection.
*
* @return bool
*/
inline bool hasAdditionalSections() const
{
return _flags & additionalSections;
}
/**
* @brief Indicates if this event log is for a power fault.
*
* This comes from a field in the message registry for BMC
* generated PELs.
*
* @return bool
*/
inline bool isPowerFaultEvent() const
{
return _flags & powerFaultEvent;
}
/**
* @brief Get the _hexData[] index to use based on the corresponding
* SRC word number.
*
* Converts the specification nomenclature to this data structure.
* See the _hexData documentation below for more information.
*
* @param[in] wordNum - The SRC word number, as defined by the spec.
*
* @return size_t The corresponding index into _hexData.
*/
inline size_t getWordIndexFromWordNum(size_t wordNum) const
{
assert(wordNum >= 2 && wordNum <= 9);
return wordNum - 2;
}
/**
* @brief Get section in JSON.
* @param[in] registry - Registry object reference
* @param[in] plugins - Vector of strings of plugins found in filesystem
* @param[in] creatorID - Creator Subsystem ID from Private Header
* @return std::optional<std::string> - SRC section's JSON
*/
std::optional<std::string> getJSON(message::Registry& registry,
const std::vector<std::string>& plugins,
uint8_t creatorID) const override;
/**
* @brief Get error details based on refcode and hexwords
* @param[in] registry - Registry object
* @param[in] type - detail level enum value : single message or full json
* @param[in] toCache - boolean to cache registry in memory, default=false
* @return std::optional<std::string> - Error details
*/
std::optional<std::string> getErrorDetails(message::Registry& registry,
DetailLevel type,
bool toCache = false) const;
/**
* @brief Says if this SRC was created by the BMC (i.e. this code).
*
* @return bool - If created by the BMC or not
*/
bool isBMCSRC() const;
private:
/**
* @brief Fills in the user defined hex words from the
* AdditionalData fields.
*
* When creating this section from a message registry entry,
* that entry has a field that says which AdditionalData property
* fields to use to fill in the user defined hex data words 6-9
* (which correspond to hexData words 4-7).
*
* For example, given that AdditionalData is a map of string keys
* to string values, find the AdditionalData value for AdditionalData
* key X, convert it to a uint32_t, and save it in user data word Y.
*
* @param[in] regEntry - The message registry entry for the error
* @param[in] additionalData - The AdditionalData map
*/
void setUserDefinedHexWords(const message::Entry& regEntry,
const AdditionalData& additionalData);
/**
* @brief Fills in the object from the stream data
*
* @param[in] stream - The stream to read from
*/
void unflatten(Stream& stream);
/**
* @brief Says if the word number is in the range of user defined words.
*
* This is only used for BMC generated SRCs, where words 6 - 9 are the
* user defined ones, meaning that setUserDefinedHexWords() will be
* used to fill them in based on the contents of the OpenBMC event log.
*
* @param[in] wordNum - The SRC word number, as defined by the spec.
*
* @return bool - If this word number can be filled in by the creator.
*/
inline bool isUserDefinedWord(size_t wordNum) const
{
return (wordNum >= 6) && (wordNum <= 9);
}
/**
* @brief Sets the SRC format byte in the hex word data.
*/
inline void setBMCFormat()
{
_hexData[0] |= bmcSRCFormat;
}
/**
* @brief Sets the hex word field that specifies which BMC
* (primary vs backup) created the error.
*
* Can be hardcoded until there are systems with redundant BMCs.
*/
inline void setBMCPosition()
{
_hexData[1] |= primaryBMCPosition;
}
/**
* @brief Sets the motherboard CCIN hex word field
*
* @param[in] dataIface - The DataInterface object
*/
void setMotherboardCCIN(const DataInterfaceBase& dataIface);
/**
* @brief Sets an error status bit in the SRC.
*
* @param[in] flag - The flag to set
*/
void setErrorStatusFlag(ErrorStatusFlags flag)
{
_hexData[3] |= static_cast<uint32_t>(flag);
}
/**
* @brief Validates the section contents
*
* Updates _valid (in Section) with the results.
*/
void validate() override;
/**
* @brief Get error description from message registry
* @param[in] regEntry - The message registry entry for the error
* @return std::optional<std::string> - Error message
*/
std::optional<std::string>
getErrorMessage(const message::Entry& regEntry) const;
/**
* @brief Get Callout info in JSON
* @return std::optional<std::string> - Callout details
*/
std::optional<std::string> getCallouts() const;
/**
* @brief Checks the AdditionalData property and the message registry
* JSON and adds any necessary callouts.
*
* The callout sources are the AdditionalData event log property
* and the message registry JSON.
*
* @param[in] regEntry - The message registry entry for the error
* @param[in] additionalData - The AdditionalData values
* @param[in] jsonCallouts - The array of JSON callouts, or an empty object
* @param[in] dataIface - The DataInterface object
*/
void addCallouts(const message::Entry& regEntry,
const AdditionalData& additionalData,
const nlohmann::json& jsonCallouts,
const DataInterfaceBase& dataIface);
/**
* @brief Adds a FRU callout based on an inventory path
*
* @param[in] inventoryPath - The inventory item to call out
* @param[in] priority - An optional priority (uses high if nullopt)
* @param[in] locationCode - The expanded location code (or look it up)
* @param[in] dataIface - The DataInterface object
* @param[in] mrus - The MRUs to add to the callout
*/
void
addInventoryCallout(const std::string& inventoryPath,
const std::optional<CalloutPriority>& priority,
const std::optional<std::string>& locationCode,
const DataInterfaceBase& dataIface,
const std::vector<src::MRU::MRUCallout>& mrus = {});
/**
* @brief Returns the callouts to use from the registry entry.
*
* @param[in] regEntry - The message registry entry for the error
* @param[in] additionalData - The AdditionalData property
* @param[in] dataIface - The DataInterface object
*/
std::vector<message::RegistryCallout>
getRegistryCallouts(const message::Entry& regEntry,
const AdditionalData& additionalData,
const DataInterfaceBase& dataIface);
/**
* @brief Adds the FRU callouts from the list of registry callouts
* passed in to the SRC.
*
* The last parameter is used only in a special case when the first
* callout is a symbolic FRU with a trusted location code. See the
* addRegistryCallout documentation.
*
* @param[in] callouts - The message registry callouts to add
* @param[in] dataIface - The DataInterface object
* @param[in] trustedSymbolicFRUInvPath - The optional inventory path used
* in the symbolic FRU case.
*/
void addRegistryCallouts(
const std::vector<message::RegistryCallout>& callouts,
const DataInterfaceBase& dataIface,
std::optional<std::string> trustedSymbolicFRUInvPath);
/**
* @brief Adds a single FRU callout from the message registry.
*
* If the last parameter is filled in, and the registry callout is a
* symbolic FRU callout with a trusted location code, and it has the
* 'useInventoryLocCode' member set to true, then the location code of
* that inventory item will be what is used for that trusted location code.
*
* @param[in] callout - The registry callout structure
* @param[in] dataIface - The DataInterface object
* @param[in] trustedSymbolicFRUInvPath - The optional inventory path used
* in the symbolic FRU case.
*/
void addRegistryCallout(
const message::RegistryCallout& callout,
const DataInterfaceBase& dataIface,
const std::optional<std::string>& trustedSymbolicFRUInvPath);
/**
* @brief Creates the Callouts object _callouts
* so that callouts can be added to it.
*/
void createCalloutsObject()
{
if (!_callouts)
{
_callouts = std::make_unique<src::Callouts>();
_flags |= additionalSections;
}
}
/**
* @brief Adds any FRU callouts based on a device path in the
* AdditionalData parameter.
*
* @param[in] additionalData - The AdditionalData values
* @param[in] dataIface - The DataInterface object
*/
void addDevicePathCallouts(const AdditionalData& additionalData,
const DataInterfaceBase& dataIface);
/**
* @brief Adds any FRU callouts specified in the incoming JSON.
*
* @param[in] jsonCallouts - The JSON array of callouts
* @param[in] dataIface - The DataInterface object
*/
void addJSONCallouts(const nlohmann::json& jsonCallouts,
const DataInterfaceBase& dataIface);
/**
* @brief Adds a single callout based on the JSON
*
* @param[in] jsonCallouts - A single callout entry
* @param[in] dataIface - The DataInterface object
*/
void addJSONCallout(const nlohmann::json& jsonCallout,
const DataInterfaceBase& dataIface);
/**
* @brief Extracts a CalloutPriority value from the json
* using the 'Priority' key.
*
* @param[in] json - A JSON object that contains the priority key
*
* @return CalloutPriority - The priority value
*/
CalloutPriority getPriorityFromJSON(const nlohmann::json& json);
/**
* @brief Exracts MRU values and their priorities from the
* input JSON array.
*
* @param[in] mruJSON - The JSON array
*/
std::vector<src::MRU::MRUCallout>
getMRUsFromJSON(const nlohmann::json& mruJSON);
/**
* @brief The SRC version field
*/
uint8_t _version;
/**
* @brief The SRC flags field
*/
uint8_t _flags;
/**
* @brief A byte of reserved data after the flags field
*/
uint8_t _reserved1B;
/**
* @brief The hex data word count.
*
* To be compatible with previous versions of SRCs, this is
* number of hex words (8) + 1 = 9.
*/
uint8_t _wordCount;
/**
* @brief Two bytes of reserved data after the hex word count
*/
uint16_t _reserved2B;
/**
* @brief The total size of the SRC section, not including the section
* header.
*/
uint16_t _size;
/**
* @brief The SRC 'hex words'.
*
* In the spec these are referred to as SRC words 2 - 9 as words 0 and 1
* are filled by the 8 bytes of fields from above.
*/
std::array<uint32_t, numSRCHexDataWords> _hexData;
/**
* @brief The 32 byte ASCII character string of the SRC
*
* It is padded with spaces to fill the 32 bytes.
* An example is:
* "BD8D1234 "
*
* That first word is what is commonly referred to as the refcode, and
* sometimes also called an SRC.
*/
std::unique_ptr<src::AsciiString> _asciiString;
/**
* @brief The callouts subsection.
*
* Optional and only created if there are callouts.
*/
std::unique_ptr<src::Callouts> _callouts;
};
} // namespace pels
} // namespace openpower