diff options
author | Aatir Manzur <aatrapps@gmail.com> | 2019-09-06 13:30:48 -0500 |
---|---|---|
committer | Matt Spinler <spinler@us.ibm.com> | 2019-10-09 08:13:30 -0500 |
commit | 51c9263f080fe794d62724a35e44dc1cfff75415 (patch) | |
tree | a238eb121bb90102f2ef2e7756d70280e152a51a | |
parent | 07eefc543b36f9fdb7d7b7ff2a64018d0770bc31 (diff) | |
download | phosphor-logging-51c9263f080fe794d62724a35e44dc1cfff75415.tar.gz phosphor-logging-51c9263f080fe794d62724a35e44dc1cfff75415.zip |
PEL: User Data class
This class is used for accessing the UserData section of a PEL.
This section contains free format data that can be identified by the
component ID, subtype, and version fields in the section header.
Signed-off-by: Aatir Manzur <aatrapps@gmail.com>
Signed-off-by: Matt Spinler <spinler@us.ibm.com>
Change-Id: I1223f84353e81202d1ff63c00f3d926cda4994e5
-rw-r--r-- | extensions/openpower-pels/openpower-pels.mk | 1 | ||||
-rw-r--r-- | extensions/openpower-pels/section_factory.cpp | 4 | ||||
-rw-r--r-- | extensions/openpower-pels/user_data.cpp | 79 | ||||
-rw-r--r-- | extensions/openpower-pels/user_data.hpp | 105 | ||||
-rw-r--r-- | test/openpower-pels/Makefile.include | 11 | ||||
-rw-r--r-- | test/openpower-pels/user_data_test.cpp | 91 |
6 files changed, 291 insertions, 0 deletions
diff --git a/extensions/openpower-pels/openpower-pels.mk b/extensions/openpower-pels/openpower-pels.mk index cca1228..c74f205 100644 --- a/extensions/openpower-pels/openpower-pels.mk +++ b/extensions/openpower-pels/openpower-pels.mk @@ -15,4 +15,5 @@ phosphor_log_manager_SOURCES += \ extensions/openpower-pels/repository.cpp \ extensions/openpower-pels/section_factory.cpp \ extensions/openpower-pels/severity.cpp \ + extensions/openpower-pels/user_data.cpp \ extensions/openpower-pels/user_header.cpp diff --git a/extensions/openpower-pels/section_factory.cpp b/extensions/openpower-pels/section_factory.cpp index 69274c0..11d8386 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 "user_data.hpp" #include "user_header.hpp" namespace openpower @@ -32,6 +33,9 @@ std::unique_ptr<Section> create(Stream& pelData) case static_cast<uint16_t>(SectionID::privateHeader): section = std::make_unique<PrivateHeader>(pelData); break; + case static_cast<uint16_t>(SectionID::userData): + section = std::make_unique<UserData>(pelData); + break; case static_cast<uint16_t>(SectionID::userHeader): section = std::make_unique<UserHeader>(pelData); break; diff --git a/extensions/openpower-pels/user_data.cpp b/extensions/openpower-pels/user_data.cpp new file mode 100644 index 0000000..f2cb282 --- /dev/null +++ b/extensions/openpower-pels/user_data.cpp @@ -0,0 +1,79 @@ +#include "user_data.hpp" + +#include "pel_types.hpp" + +#include <phosphor-logging/log.hpp> + +namespace openpower +{ +namespace pels +{ + +using namespace phosphor::logging; + +void UserData::unflatten(Stream& stream) +{ + stream >> _header; + + if (_header.size <= SectionHeader::flattenedSize()) + { + throw std::out_of_range( + "UserData::unflatten: SectionHeader::size field too small"); + } + + size_t dataLength = _header.size - SectionHeader::flattenedSize(); + _data.resize(dataLength); + + stream >> _data; +} + +void UserData::flatten(Stream& stream) +{ + stream << _header << _data; +} + +UserData::UserData(Stream& pel) +{ + try + { + unflatten(pel); + validate(); + } + catch (const std::exception& e) + { + log<level::ERR>("Cannot unflatten user data", + entry("ERROR=%s", e.what())); + _valid = false; + } +} + +UserData::UserData(uint16_t componentID, uint8_t subType, uint8_t version, + const std::vector<uint8_t>& data) +{ + _header.id = static_cast<uint16_t>(SectionID::userData); + _header.size = Section::flattenedSize() + data.size(); + _header.version = version; + _header.subType = subType; + _header.componentID = componentID; + + _data = data; + + _valid = true; +} + +void UserData::validate() +{ + if (header().id != static_cast<uint16_t>(SectionID::userData)) + { + log<level::ERR>("Invalid user data section ID", + entry("ID=0x%X", header().id)); + _valid = false; + } + else + { + _valid = true; + } +} + +} // namespace pels +} // namespace openpower diff --git a/extensions/openpower-pels/user_data.hpp b/extensions/openpower-pels/user_data.hpp new file mode 100644 index 0000000..98bf0a8 --- /dev/null +++ b/extensions/openpower-pels/user_data.hpp @@ -0,0 +1,105 @@ +#pragma once + +#include "section.hpp" +#include "stream.hpp" + +namespace openpower +{ +namespace pels +{ + +/** + * @class UserData + * + * This represents the User Data section in a PEL. It is free form data + * that the creator knows the contents of. The component ID, version, + * and sub-type fields in the section header are used to identify the + * format. + * + * The Section base class handles the section header structure that every + * PEL section has at offset zero. + */ +class UserData : public Section +{ + public: + UserData() = delete; + ~UserData() = default; + UserData(const UserData&) = default; + UserData& operator=(const UserData&) = default; + UserData(UserData&&) = default; + UserData& operator=(UserData&&) = default; + + /** + * @brief Constructor + * + * Fills in this class's data fields from the stream. + * + * @param[in] pel - the PEL data stream + */ + explicit UserData(Stream& pel); + + /** + * @brief Constructor + * + * Create a valid UserData object with the passed in data. + * + * The component ID, subtype, and version are used to identify + * the data to know which parser to call. + * + * @param[in] componentID - Component ID of the creator + * @param[in] subType - The type of user data + * @param[in] version - The version of the data + */ + UserData(uint16_t componentID, uint8_t subType, uint8_t version, + const std::vector<uint8_t>& data); + + /** + * @brief Flatten the section into the stream + * + * @param[in] stream - The stream to write to + */ + void flatten(Stream& stream) override; + + /** + * @brief Returns the size of this section when flattened into a PEL + * + * @return size_t - the size of the section + */ + size_t flattenedSize() + { + return Section::flattenedSize() + _data.size(); + } + + /** + * @brief Returns the raw section data + * + * @return std::vector<uint8_t>& + */ + const std::vector<uint8_t>& data() const + { + return _data; + } + + private: + /** + * @brief Fills in the object from the stream data + * + * @param[in] stream - The stream to read from + */ + void unflatten(Stream& stream); + + /** + * @brief Validates the section contents + * + * Updates _valid (in Section) with the results. + */ + void validate() override; + + /** + * @brief The section data + */ + std::vector<uint8_t> _data; +}; + +} // namespace pels +} // namespace openpower diff --git a/test/openpower-pels/Makefile.include b/test/openpower-pels/Makefile.include index f2e3126..b6b49aa 100644 --- a/test/openpower-pels/Makefile.include +++ b/test/openpower-pels/Makefile.include @@ -17,6 +17,7 @@ check_PROGRAMS += \ section_header_test \ severity_test \ stream_test \ + user_data_test \ user_header_test pel_objects = \ @@ -31,6 +32,7 @@ pel_objects = \ $(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/user_data.o \ $(top_builddir)/extensions/openpower-pels/user_header.o additional_data_test_SOURCES = %reldir%/additional_data_test.cpp @@ -179,3 +181,12 @@ generic_section_test_LDADD = \ $(test_ldadd) \ $(top_builddir)/extensions/openpower-pels/generic.o generic_section_test_LDFLAGS = $(test_ldflags) + +user_data_test_SOURCES = \ + %reldir%/user_data_test.cpp %reldir%/pel_utils.cpp +user_data_test_CPPFLAGS = $(test_cppflags) +user_data_test_CXXFLAGS = $(test_cxxflags) +user_data_test_LDADD = \ + $(test_ldadd) \ + $(top_builddir)/extensions/openpower-pels/user_data.o +user_data_test_LDFLAGS = $(test_ldflags) diff --git a/test/openpower-pels/user_data_test.cpp b/test/openpower-pels/user_data_test.cpp new file mode 100644 index 0000000..be3f5cb --- /dev/null +++ b/test/openpower-pels/user_data_test.cpp @@ -0,0 +1,91 @@ +#include "extensions/openpower-pels/user_data.hpp" +#include "pel_utils.hpp" + +#include <gtest/gtest.h> + +using namespace openpower::pels; + +std::vector<uint8_t> udSectionData{0x55, 0x44, // ID 'UD' + 0x00, 0x10, // Size + 0x01, 0x02, // version, subtype + 0x03, 0x04, // comp ID + + // Data + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18}; + +TEST(UserDataTest, UnflattenFlattenTest) +{ + Stream stream(udSectionData); + UserData ud(stream); + + EXPECT_TRUE(ud.valid()); + EXPECT_EQ(ud.header().id, 0x5544); + EXPECT_EQ(ud.header().size, udSectionData.size()); + EXPECT_EQ(ud.header().version, 0x01); + EXPECT_EQ(ud.header().subType, 0x02); + EXPECT_EQ(ud.header().componentID, 0x0304); + + const auto& data = ud.data(); + + // The data itself starts after the header + EXPECT_EQ(data.size(), udSectionData.size() - 8); + + for (size_t i = 0; i < data.size(); i++) + { + EXPECT_EQ(data[i], udSectionData[i + 8]); + } + + // Now flatten + std::vector<uint8_t> newData; + Stream newStream(newData); + ud.flatten(newStream); + + EXPECT_EQ(udSectionData, newData); +} + +TEST(UserDataTest, BadDataTest) +{ + auto data = udSectionData; + data.resize(4); + + Stream stream(data); + UserData ud(stream); + EXPECT_FALSE(ud.valid()); +} + +TEST(UserDataTest, BadSizeFieldTest) +{ + auto data = udSectionData; + + { + data[3] = 0xFF; // Set the size field too large + Stream stream(data); + UserData ud(stream); + EXPECT_FALSE(ud.valid()); + } + { + data[3] = 0x7; // Set the size field too small + Stream stream(data); + UserData ud(stream); + EXPECT_FALSE(ud.valid()); + } +} + +TEST(UserDataTest, ConstructorTest) +{ + std::vector<uint8_t> data{0x11, 0x22, 0x33, 0x44, 0x55, 0x66}; + + UserData ud(0x1112, 0x42, 0x01, data); + EXPECT_TRUE(ud.valid()); + + EXPECT_EQ(ud.header().id, 0x5544); + EXPECT_EQ(ud.header().size, 14); + EXPECT_EQ(ud.header().version, 0x01); + EXPECT_EQ(ud.header().subType, 0x42); + EXPECT_EQ(ud.header().componentID, 0x1112); + + const auto& d = ud.data(); + + EXPECT_EQ(d, data); +} |