PEL: Add PrivateHeader class
The first section in a PEL is always the 'Private Header' section. This
commit adds a class to represent that. Right now, the only constructor
available is filling in its data fields from a PEL stream.
The Section base class, which will be the base class of all PEL
sections, is also being introduced here. It contains the section header
structure, and a valid flag that derived classes can use.
Signed-off-by: Matt Spinler <spinler@us.ibm.com>
Change-Id: Ia5806017155fe1ef29ea57bf8ab202ff861bde2e
diff --git a/test/openpower-pels/Makefile.include b/test/openpower-pels/Makefile.include
index 07e596d..288a5db 100644
--- a/test/openpower-pels/Makefile.include
+++ b/test/openpower-pels/Makefile.include
@@ -3,9 +3,14 @@
check_PROGRAMS += \
additional_data_test \
bcd_time_test \
+ private_header_test \
section_header_test \
stream_test
+pel_objects = \
+ $(top_builddir)/extensions/openpower-pels/bcd_time.o \
+ $(top_builddir)/extensions/openpower-pels/private_header.o
+
additional_data_test_SOURCES = %reldir%/additional_data_test.cpp
additional_data_test_CPPFLAGS = $(test_cppflags)
additional_data_test_CXXFLAGS = $(test_cxxflags)
@@ -32,4 +37,13 @@
section_header_test_CPPFLAGS = $(test_cppflags)
section_header_test_CXXFLAGS = $(test_cxxflags)
section_header_test_LDADD = $(test_ldadd)
-section_header_test_LDFLAGS = $(test_ldflags)
\ No newline at end of file
+section_header_test_LDFLAGS = $(test_ldflags)
+
+private_header_test_SOURCES = \
+ %reldir%/private_header_test.cpp %reldir%/pel_utils.cpp
+private_header_test_CPPFLAGS = $(test_cppflags)
+private_header_test_CXXFLAGS = $(test_cxxflags)
+private_header_test_LDADD = \
+ $(test_ldadd) \
+ $(pel_objects)
+private_header_test_LDFLAGS = $(test_ldflags)
diff --git a/test/openpower-pels/pel_utils.cpp b/test/openpower-pels/pel_utils.cpp
new file mode 100644
index 0000000..4e4c32a
--- /dev/null
+++ b/test/openpower-pels/pel_utils.cpp
@@ -0,0 +1,57 @@
+#include "pel_utils.hpp"
+
+#include "extensions/openpower-pels/private_header.hpp"
+
+#include <fstream>
+
+#include <gtest/gtest.h>
+
+namespace fs = std::filesystem;
+using namespace openpower::pels;
+
+constexpr uint8_t simplePEL[] = {
+ // private header section header
+ 0x50, 0x48, // ID 'PH'
+ 0x00, 0x30, // Size
+ 0x01, 0x02, // version, subtype
+ 0x03, 0x04, // comp ID
+
+ // private header
+ 0x20, 0x30, 0x05, 0x09, 0x11, 0x1E, 0x1, 0x63, // create timestamp
+ 0x20, 0x31, 0x06, 0x0F, 0x09, 0x22, 0x3A, 0x00, // commit timestamp
+ 0xAA, // creatorID
+ 0x00, // logtype
+ 0x00, // reserved
+ 0x02, // section count
+ 0x90, 0x91, 0x92, 0x93, // OpenBMC log ID
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0, // creator version
+ 0x50, 0x51, 0x52, 0x53, // plid
+ 0x80, 0x81, 0x82, 0x83 // id
+
+};
+
+std::unique_ptr<std::vector<uint8_t>> pelDataFactory(TestPelType type)
+{
+ std::unique_ptr<std::vector<uint8_t>> data;
+ switch (type)
+ {
+ case TestPelType::pelSimple:
+ data = std::make_unique<std::vector<uint8_t>>(
+ simplePEL, simplePEL + sizeof(simplePEL));
+ break;
+ case TestPelType::privateHeaderSimple:
+ data = std::make_unique<std::vector<uint8_t>>(
+ simplePEL, simplePEL + PrivateHeader::flattenedSize());
+ break;
+ }
+ return data;
+}
+
+std::unique_ptr<std::vector<uint8_t>> readPELFile(const fs::path& path)
+{
+ std::ifstream file{path};
+
+ auto pel = std::make_unique<std::vector<uint8_t>>(
+ std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>());
+ return pel;
+}
diff --git a/test/openpower-pels/pel_utils.hpp b/test/openpower-pels/pel_utils.hpp
new file mode 100644
index 0000000..bc4e05d
--- /dev/null
+++ b/test/openpower-pels/pel_utils.hpp
@@ -0,0 +1,33 @@
+#include <filesystem>
+#include <memory>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+/**
+ * @brief Tells the factory which PEL to create
+ */
+enum class TestPelType
+{
+ pelSimple,
+ privateHeaderSimple
+};
+
+/**
+ * @brief PEL data factory, for testing
+ *
+ * @param[in] type - the type of data to create
+ *
+ * @return std::unique_ptr<std::vector<uint8_t>> - the PEL data
+ */
+std::unique_ptr<std::vector<uint8_t>> pelDataFactory(TestPelType type);
+
+/**
+ * @brief Helper function to read raw PEL data from a file
+ *
+ * @param[in] path - the path to read
+ *
+ * @return std::unique_ptr<std::vector<uint8_t>> - the data from the file
+ */
+std::unique_ptr<std::vector<uint8_t>>
+ readPELFile(const std::filesystem::path& path);
diff --git a/test/openpower-pels/private_header_test.cpp b/test/openpower-pels/private_header_test.cpp
new file mode 100644
index 0000000..40a1ad2
--- /dev/null
+++ b/test/openpower-pels/private_header_test.cpp
@@ -0,0 +1,126 @@
+#include "extensions/openpower-pels/private_header.hpp"
+#include "pel_utils.hpp"
+
+#include <gtest/gtest.h>
+
+using namespace openpower::pels;
+
+TEST(PrivateHeaderTest, SizeTest)
+{
+ EXPECT_EQ(PrivateHeader::flattenedSize(), 48);
+}
+
+TEST(PrivateHeaderTest, UnflattenFlattenTest)
+{
+ auto data = pelDataFactory(TestPelType::privateHeaderSimple);
+
+ Stream stream(*data);
+ PrivateHeader ph(stream);
+ EXPECT_EQ(ph.valid(), true);
+
+ EXPECT_EQ(ph.header().id, 0x5048);
+ EXPECT_EQ(ph.header().size, PrivateHeader::flattenedSize());
+ EXPECT_EQ(ph.header().version, 0x01);
+ EXPECT_EQ(ph.header().subType, 0x02);
+ EXPECT_EQ(ph.header().componentID, 0x0304);
+
+ auto& ct = ph.createTimestamp();
+ EXPECT_EQ(ct.yearMSB, 0x20);
+ EXPECT_EQ(ct.yearLSB, 0x30);
+ EXPECT_EQ(ct.month, 0x05);
+ EXPECT_EQ(ct.day, 0x09);
+ EXPECT_EQ(ct.hour, 0x011);
+ EXPECT_EQ(ct.minutes, 0x1E);
+ EXPECT_EQ(ct.seconds, 0x01);
+ EXPECT_EQ(ct.hundredths, 0x63);
+
+ auto& mt = ph.commitTimestamp();
+ EXPECT_EQ(mt.yearMSB, 0x20);
+ EXPECT_EQ(mt.yearLSB, 0x31);
+ EXPECT_EQ(mt.month, 0x06);
+ EXPECT_EQ(mt.day, 0x0F);
+ EXPECT_EQ(mt.hour, 0x09);
+ EXPECT_EQ(mt.minutes, 0x22);
+ EXPECT_EQ(mt.seconds, 0x3A);
+ EXPECT_EQ(mt.hundredths, 0x00);
+
+ EXPECT_EQ(ph.creatorID(), 0xAA);
+ EXPECT_EQ(ph.logType(), 0x00);
+ EXPECT_EQ(ph.sectionCount(), 0x02);
+ EXPECT_EQ(ph.obmcLogID(), 0x90919293);
+
+ char expected[] = {0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x00};
+ EXPECT_TRUE(memcmp(ph.creatorVersion().version, expected, 8) == 0);
+
+ EXPECT_EQ(ph.plid(), 0x50515253);
+ EXPECT_EQ(ph.id(), 0x80818283);
+
+ // Now flatten into a vector and check that this vector
+ // matches the original one.
+ std::vector<uint8_t> newData;
+ Stream newStream(newData);
+
+ newStream << ph;
+ EXPECT_EQ(*data, newData);
+
+ // Change a field, then flatten and unflatten again
+ ph.creatorID() = 0x55;
+
+ newStream.offset(0);
+ newData.clear();
+ newStream << ph;
+ EXPECT_NE(*data, newData);
+
+ newStream.offset(0);
+ PrivateHeader newPH(newStream);
+
+ EXPECT_TRUE(newPH.valid());
+ EXPECT_EQ(newPH.creatorID(), 0x55);
+}
+
+TEST(PrivateHeaderTest, ShortDataTest)
+{
+ auto data = pelDataFactory(TestPelType::privateHeaderSimple);
+ data->resize(PrivateHeader::flattenedSize() - 1);
+ Stream stream(*data);
+
+ PrivateHeader ph(stream);
+
+ EXPECT_EQ(ph.valid(), false);
+}
+
+TEST(PrivateHeaderTest, CorruptDataTest1)
+{
+ auto data = pelDataFactory(TestPelType::privateHeaderSimple);
+ Stream stream(*data);
+
+ data->at(0) = 0; // corrupt the section ID
+
+ PrivateHeader ph(stream);
+
+ EXPECT_EQ(ph.valid(), false);
+}
+
+TEST(PrivateHeaderTest, CorruptDataTest2)
+{
+ auto data = pelDataFactory(TestPelType::privateHeaderSimple);
+ Stream stream(*data);
+
+ data->at(4) = 0x22; // corrupt the version
+
+ PrivateHeader ph(stream);
+
+ EXPECT_EQ(ph.valid(), false);
+}
+
+TEST(PrivateHeaderTest, CorruptDataTest3)
+{
+ auto data = pelDataFactory(TestPelType::privateHeaderSimple);
+ Stream stream(*data);
+
+ data->at(27) = 1; // corrupt the section count
+
+ PrivateHeader ph(stream);
+
+ EXPECT_EQ(ph.valid(), false);
+}