summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatt Spinler <spinler@us.ibm.com>2019-10-09 13:37:38 -0500
committerMatt Spinler <spinler@us.ibm.com>2019-10-22 14:09:56 +0000
commitf9bae18539eca100632d462083698b57d9687c82 (patch)
tree1fa8904d5e82750314bcbc1bbf0b0b6ee957b26c
parent32f13c915fa4b27520ca0aea476804c37f5516b9 (diff)
downloadphosphor-logging-f9bae18539eca100632d462083698b57d9687c82.tar.gz
phosphor-logging-f9bae18539eca100632d462083698b57d9687c82.zip
PEL: Add SRC PEL section class
This section consists of: - An 8B header - 8 4B words of hex data - Some data is predefined based on the SRC format, some is free format. - A 32B ASCII character string (The AsciiString class) - An optional section for FRU callouts (The Callouts class) Usually, the term SRC (System Reference Code) refers to the contents of the ASCII string and the hex data words, which can then be looked up in service documentation to find the meaning of the event log. This PEL section wraps this pure SRC with additional data like callouts. This commit only adds support for unflattening the section from an existing PEL, and flattening it again. Future commits will add support for creating an SRC from message registry data. Signed-off-by: Matt Spinler <spinler@us.ibm.com> Change-Id: I3dd97c6aca59cc6d6d6fadef84465164090d5658
-rw-r--r--extensions/openpower-pels/openpower-pels.mk1
-rw-r--r--extensions/openpower-pels/section_factory.cpp5
-rw-r--r--extensions/openpower-pels/src.cpp87
-rw-r--r--extensions/openpower-pels/src.hpp233
-rw-r--r--test/openpower-pels/Makefile.include25
-rw-r--r--test/openpower-pels/pel_utils.cpp72
-rw-r--r--test/openpower-pels/pel_utils.hpp5
-rw-r--r--test/openpower-pels/src_test.cpp82
8 files changed, 509 insertions, 1 deletions
diff --git a/extensions/openpower-pels/openpower-pels.mk b/extensions/openpower-pels/openpower-pels.mk
index a10a4a9..ef954ce 100644
--- a/extensions/openpower-pels/openpower-pels.mk
+++ b/extensions/openpower-pels/openpower-pels.mk
@@ -19,6 +19,7 @@ phosphor_log_manager_SOURCES += \
extensions/openpower-pels/private_header.cpp \
extensions/openpower-pels/registry.cpp \
extensions/openpower-pels/repository.cpp \
+ extensions/openpower-pels/src.cpp \
extensions/openpower-pels/section_factory.cpp \
extensions/openpower-pels/severity.cpp \
extensions/openpower-pels/user_data.cpp \
diff --git a/extensions/openpower-pels/section_factory.cpp b/extensions/openpower-pels/section_factory.cpp
index 11d8386..a95da12 100644
--- a/extensions/openpower-pels/section_factory.cpp
+++ b/extensions/openpower-pels/section_factory.cpp
@@ -4,6 +4,7 @@
#include "generic.hpp"
#include "pel_types.hpp"
#include "private_header.hpp"
+#include "src.hpp"
#include "user_data.hpp"
#include "user_header.hpp"
@@ -42,6 +43,10 @@ std::unique_ptr<Section> create(Stream& pelData)
case static_cast<uint16_t>(SectionID::failingMTMS):
section = std::make_unique<FailingMTMS>(pelData);
break;
+ case static_cast<uint16_t>(SectionID::primarySRC):
+ case static_cast<uint16_t>(SectionID::secondarySRC):
+ section = std::make_unique<SRC>(pelData);
+ break;
default:
// A generic object, but at least an object.
section = std::make_unique<Generic>(pelData);
diff --git a/extensions/openpower-pels/src.cpp b/extensions/openpower-pels/src.cpp
new file mode 100644
index 0000000..7fd7b0e
--- /dev/null
+++ b/extensions/openpower-pels/src.cpp
@@ -0,0 +1,87 @@
+#include "src.hpp"
+
+#include <phosphor-logging/log.hpp>
+
+namespace openpower
+{
+namespace pels
+{
+
+using namespace phosphor::logging;
+
+void SRC::unflatten(Stream& stream)
+{
+ stream >> _header >> _version >> _flags >> _reserved1B >> _wordCount >>
+ _reserved2B >> _size;
+
+ for (auto& word : _hexData)
+ {
+ stream >> word;
+ }
+
+ _asciiString = std::make_unique<src::AsciiString>(stream);
+
+ if (hasAdditionalSections())
+ {
+ // The callouts section is currently the only extra subsection type
+ _callouts = std::make_unique<src::Callouts>(stream);
+ }
+}
+
+void SRC::flatten(Stream& stream)
+{
+ stream << _header << _version << _flags << _reserved1B << _wordCount
+ << _reserved2B << _size;
+
+ for (auto& word : _hexData)
+ {
+ stream << word;
+ }
+
+ _asciiString->flatten(stream);
+
+ if (_callouts)
+ {
+ _callouts->flatten(stream);
+ }
+}
+
+SRC::SRC(Stream& pel)
+{
+ try
+ {
+ unflatten(pel);
+ validate();
+ }
+ catch (const std::exception& e)
+ {
+ log<level::ERR>("Cannot unflatten SRC", entry("ERROR=%s", e.what()));
+ _valid = false;
+ }
+}
+
+void SRC::validate()
+{
+ bool failed = false;
+
+ if ((header().id != static_cast<uint16_t>(SectionID::primarySRC)) &&
+ (header().id != static_cast<uint16_t>(SectionID::secondarySRC)))
+ {
+ log<level::ERR>("Invalid SRC section ID",
+ entry("ID=0x%X", header().id));
+ failed = true;
+ }
+
+ // Check the version in the SRC, not in the header
+ if (_version != srcSectionVersion)
+ {
+ log<level::ERR>("Invalid SRC section version",
+ entry("VERSION=0x%X", _version));
+ failed = true;
+ }
+
+ _valid = failed ? false : true;
+}
+
+} // namespace pels
+} // namespace openpower
diff --git a/extensions/openpower-pels/src.hpp b/extensions/openpower-pels/src.hpp
new file mode 100644
index 0000000..365f12b
--- /dev/null
+++ b/extensions/openpower-pels/src.hpp
@@ -0,0 +1,233 @@
+#pragma once
+
+#include "additional_data.hpp"
+#include "ascii_string.hpp"
+#include "callouts.hpp"
+#include "pel_types.hpp"
+#include "section.hpp"
+#include "stream.hpp"
+
+namespace openpower
+{
+namespace pels
+{
+
+constexpr size_t numSRCHexDataWords = 8;
+constexpr uint8_t srcSectionVersion = 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
+ };
+
+ 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 Flatten the section into the stream
+ *
+ * @param[in] stream - The stream to write to
+ */
+ void flatten(Stream& stream) 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;
+ }
+
+ private:
+ /**
+ * @brief Fills in the object from the stream data
+ *
+ * @param[in] stream - The stream to read from
+ */
+ void unflatten(Stream& stream);
+
+ /**
+ * @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 & static_cast<uint8_t>(HeaderFlags::additionalSections);
+ }
+
+ /**
+ * @brief Validates the section contents
+ *
+ * Updates _valid (in Section) with the results.
+ */
+ void validate() override;
+
+ /**
+ * @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
diff --git a/test/openpower-pels/Makefile.include b/test/openpower-pels/Makefile.include
index 3bc760f..d110cc1 100644
--- a/test/openpower-pels/Makefile.include
+++ b/test/openpower-pels/Makefile.include
@@ -20,6 +20,7 @@ check_PROGRAMS += \
repository_test \
section_header_test \
severity_test \
+ src_test \
src_callout_test \
src_callouts_test \
stream_test \
@@ -27,17 +28,24 @@ check_PROGRAMS += \
user_header_test
pel_objects = \
+ $(top_builddir)/extensions/openpower-pels/ascii_string.o \
$(top_builddir)/extensions/openpower-pels/bcd_time.o \
+ $(top_builddir)/extensions/openpower-pels/callout.o \
+ $(top_builddir)/extensions/openpower-pels/callouts.o \
$(top_builddir)/extensions/openpower-pels/failing_mtms.o \
+ $(top_builddir)/extensions/openpower-pels/fru_identity.o \
$(top_builddir)/extensions/openpower-pels/generic.o \
$(top_builddir)/extensions/openpower-pels/log_id.o \
$(top_builddir)/extensions/openpower-pels/mtms.o \
+ $(top_builddir)/extensions/openpower-pels/mru.o \
+ $(top_builddir)/extensions/openpower-pels/pce_identity.o \
$(top_builddir)/extensions/openpower-pels/pel.o \
$(top_builddir)/extensions/openpower-pels/pel_values.o \
$(top_builddir)/extensions/openpower-pels/private_header.o \
$(top_builddir)/extensions/openpower-pels/registry.o \
$(top_builddir)/extensions/openpower-pels/section_factory.o \
$(top_builddir)/extensions/openpower-pels/severity.o \
+ $(top_builddir)/extensions/openpower-pels/src.o \
$(top_builddir)/extensions/openpower-pels/user_data.o \
$(top_builddir)/extensions/openpower-pels/user_header.o
@@ -258,3 +266,20 @@ src_callouts_test_LDADD = \
$(top_builddir)/extensions/openpower-pels/mtms.o \
$(top_builddir)/extensions/openpower-pels/pce_identity.o
src_callouts_test_LDFLAGS = $(test_ldflags)
+
+src_test_SOURCES = \
+ %reldir%/src_test.cpp \
+ %reldir%/pel_utils.cpp
+src_test_CPPFLAGS = $(test_cppflags)
+src_test_CXXFLAGS = $(test_cxxflags)
+src_test_LDADD = \
+ $(test_ldadd) \
+ $(top_builddir)/extensions/openpower-pels/ascii_string.o \
+ $(top_builddir)/extensions/openpower-pels/callout.o \
+ $(top_builddir)/extensions/openpower-pels/callouts.o \
+ $(top_builddir)/extensions/openpower-pels/fru_identity.o \
+ $(top_builddir)/extensions/openpower-pels/mru.o \
+ $(top_builddir)/extensions/openpower-pels/mtms.o \
+ $(top_builddir)/extensions/openpower-pels/pce_identity.o \
+ $(top_builddir)/extensions/openpower-pels/src.o
+src_test_LDFLAGS = $(test_ldflags)
diff --git a/test/openpower-pels/pel_utils.cpp b/test/openpower-pels/pel_utils.cpp
index f7c9150..109c1ce 100644
--- a/test/openpower-pels/pel_utils.cpp
+++ b/test/openpower-pels/pel_utils.cpp
@@ -78,6 +78,25 @@ std::vector<uint8_t> srcMRUCallout{
0x04, 0x04, 0x04, 0x04, // MRU ID 3
};
+std::vector<uint8_t> srcSectionNoCallouts{
+
+ // Header
+ 'P', 'S', 0x00, 0x80, 0x01, 0x01, 0x02, 0x02,
+
+ // SRC
+ 0x02, 0x00, 0x00, // version, flags, reserved
+ 0x09, 0x00, 0x00, // hex word count, reserved2B
+ 0x00, 0x48, // SRC structure size
+
+ // Hex words 2 - 9
+ 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04,
+ 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07,
+ 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09,
+ // ASCII string
+ 'B', 'D', '8', 'D', '5', '6', '7', '8', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', ' '};
+
std::unique_ptr<std::vector<uint8_t>> pelDataFactory(TestPelType type)
{
std::unique_ptr<std::vector<uint8_t>> data;
@@ -147,6 +166,59 @@ std::vector<uint8_t> srcDataFactory(TestSRCType type)
data[0] = data.size();
return data;
}
+ case TestSRCType::calloutSection2Callouts:
+ {
+ std::vector<uint8_t> data{0xC0, 0x00, 0x00,
+ 0x00}; // ID, flags, length in words
+
+ // Add 2 callouts
+ auto callout = srcDataFactory(TestSRCType::calloutStructureA);
+ data.insert(data.end(), callout.begin(), callout.end());
+
+ callout = srcDataFactory(TestSRCType::calloutStructureB);
+ data.insert(data.end(), callout.begin(), callout.end());
+
+ // Set the actual word length value at offset 2
+ Stream stream{data};
+ uint16_t wordLength = data.size() / 4;
+ stream.offset(2);
+ stream << wordLength;
+ stream.offset(0);
+
+ return data;
+ }
+ case TestSRCType::primarySRCNoCallouts:
+ {
+ return srcSectionNoCallouts;
+ }
+ case TestSRCType::primarySRC2Callouts:
+ {
+ // Start with the no-callouts SRC, and add the callouts section
+ // from above.
+ auto src = srcSectionNoCallouts;
+ auto callouts =
+ srcDataFactory(TestSRCType::calloutSection2Callouts);
+
+ src.insert(src.end(), callouts.begin(), callouts.end());
+
+ // Set the flag that says there are callouts
+ // One byte after the 8B header
+ src[8 + 1] |= 0x01;
+
+ // Set the new sizes
+ uint16_t size = src.size();
+ Stream stream{src};
+
+ stream.offset(2); // In the header
+ stream << size;
+
+ // In the SRC - the size field doesn't include the header
+ size -= 8;
+ stream.offset(8 + 6);
+ stream << size;
+
+ return src;
+ }
}
return {};
}
diff --git a/test/openpower-pels/pel_utils.hpp b/test/openpower-pels/pel_utils.hpp
index 7416c31..6d70dfa 100644
--- a/test/openpower-pels/pel_utils.hpp
+++ b/test/openpower-pels/pel_utils.hpp
@@ -68,7 +68,10 @@ enum class TestSRCType
pceIdentityStructure,
mruStructure,
calloutStructureA,
- calloutStructureB
+ calloutStructureB,
+ calloutSection2Callouts,
+ primarySRCNoCallouts,
+ primarySRC2Callouts
};
/**
diff --git a/test/openpower-pels/src_test.cpp b/test/openpower-pels/src_test.cpp
new file mode 100644
index 0000000..7af3306
--- /dev/null
+++ b/test/openpower-pels/src_test.cpp
@@ -0,0 +1,82 @@
+#include "extensions/openpower-pels/src.hpp"
+#include "pel_utils.hpp"
+
+#include <gtest/gtest.h>
+
+using namespace openpower::pels;
+
+TEST(SRCTest, UnflattenFlattenTestNoCallouts)
+{
+ auto data = srcDataFactory(TestSRCType::primarySRCNoCallouts);
+
+ Stream stream{data};
+ SRC src{stream};
+
+ EXPECT_TRUE(src.valid());
+
+ EXPECT_EQ(src.header().id, 0x5053);
+ EXPECT_EQ(src.header().size, 0x80);
+ EXPECT_EQ(src.header().version, 0x01);
+ EXPECT_EQ(src.header().subType, 0x01);
+ EXPECT_EQ(src.header().componentID, 0x0202);
+
+ EXPECT_EQ(src.version(), 0x02);
+ EXPECT_EQ(src.flags(), 0x00);
+ EXPECT_EQ(src.hexWordCount(), 9);
+ EXPECT_EQ(src.size(), 0x48);
+
+ const auto& hexwords = src.hexwordData();
+ EXPECT_EQ(0x02020202, hexwords[0]);
+ EXPECT_EQ(0x03030303, hexwords[1]);
+ EXPECT_EQ(0x04040404, hexwords[2]);
+ EXPECT_EQ(0x05050505, hexwords[3]);
+ EXPECT_EQ(0x06060606, hexwords[4]);
+ EXPECT_EQ(0x07070707, hexwords[5]);
+ EXPECT_EQ(0x08080808, hexwords[6]);
+ EXPECT_EQ(0x09090909, hexwords[7]);
+
+ EXPECT_EQ(src.asciiString(), "BD8D5678 ");
+ EXPECT_FALSE(src.callouts());
+
+ // Flatten
+ std::vector<uint8_t> newData;
+ Stream newStream{newData};
+
+ src.flatten(newStream);
+ EXPECT_EQ(data, newData);
+}
+
+TEST(SRCTest, UnflattenFlattenTest2Callouts)
+{
+ auto data = srcDataFactory(TestSRCType::primarySRC2Callouts);
+
+ Stream stream{data};
+ SRC src{stream};
+
+ EXPECT_TRUE(src.valid());
+
+ // Spot check the SRC fields, but they're the same as above
+ EXPECT_EQ(src.asciiString(), "BD8D5678 ");
+
+ // There should be 2 callouts
+ const auto& calloutsSection = src.callouts();
+ ASSERT_TRUE(calloutsSection);
+ const auto& callouts = calloutsSection->callouts();
+ EXPECT_EQ(callouts.size(), 2);
+
+ // spot check that each callout has the right substructures
+ EXPECT_TRUE(callouts.front()->fruIdentity());
+ EXPECT_FALSE(callouts.front()->pceIdentity());
+ EXPECT_FALSE(callouts.front()->mru());
+
+ EXPECT_TRUE(callouts.back()->fruIdentity());
+ EXPECT_TRUE(callouts.back()->pceIdentity());
+ EXPECT_TRUE(callouts.back()->mru());
+
+ // Flatten
+ std::vector<uint8_t> newData;
+ Stream newStream{newData};
+
+ src.flatten(newStream);
+ EXPECT_EQ(data, newData);
+}
OpenPOWER on IntegriCloud