FruUtils: Add support for finding FRU at an offset
This change adds findFRUHeader which can detect non-IPMI headers to
identify the offset for IPMI FRU data. An implementation for "$TYAN$"
has been added. The new findFRUHeader is now used by readFRUContents
to generically read IPMI FRU both at offset 0 and at a offset as
determined by findFRUHeader.
Signed-off-by: Oskar Senft <osk@google.com>
Change-Id: I4325aac7737db59aaa11359ad7a0d575957f16e7
diff --git a/test/test_fru-utils.cpp b/test/test_fru-utils.cpp
index d2f0e36..2984094 100644
--- a/test/test_fru-utils.cpp
+++ b/test/test_fru-utils.cpp
@@ -1,6 +1,8 @@
#include "FruUtils.hpp"
#include <array>
+#include<algorithm>
+#include<iterator>
#include "gtest/gtest.h"
@@ -142,3 +144,101 @@
EXPECT_EQ(calculateChecksum(data), 255);
}
+
+int64_t getDataTempl(
+ const std::vector<uint8_t>& data,
+ [[maybe_unused]] int flag,
+ [[maybe_unused]] int file,
+ [[maybe_unused]] uint16_t address,
+ uint16_t offset, uint8_t length, uint8_t* outBuf)
+{
+ if (offset >= data.size())
+ {
+ return 0;
+ }
+
+ uint16_t idx;
+ for (idx = offset;
+ idx < data.size() && idx < offset + length;
+ ++idx, ++outBuf)
+ {
+ *outBuf = data[idx];
+ }
+
+ return idx - offset;
+}
+
+TEST(FindFRUHeaderTest, InvalidHeader)
+{
+ const std::vector<uint8_t> data = {255, 16};
+ uint16_t offset = 0;
+ std::array<uint8_t, I2C_SMBUS_BLOCK_MAX> blockData;
+ auto getData = [&data](auto fl, auto fi, auto a, auto o, auto l,
+ auto* b) { return getDataTempl(data, fl, fi, a, o, l, b); };
+
+ EXPECT_FALSE(findFRUHeader(0, 0, 0, getData, "error", blockData, offset));
+}
+
+TEST(FindFRUHeaderTest, NoData)
+{
+ const std::vector<uint8_t> data = {};
+ uint16_t offset = 0;
+ std::array<uint8_t, I2C_SMBUS_BLOCK_MAX> blockData;
+ auto getData = [&data](auto fl, auto fi, auto a, auto o, auto l,
+ auto* b) { return getDataTempl(data, fl, fi, a, o, l, b); };
+
+ EXPECT_FALSE(findFRUHeader(0, 0, 0, getData, "error", blockData, offset));
+}
+
+TEST(FindFRUHeaderTest, ValidHeader)
+{
+ const std::vector<uint8_t> data = {
+ 0x01, 0x00, 0x01, 0x02, 0x03, 0x04, 0x00, 0xf5};
+ uint16_t offset = 0;
+ std::array<uint8_t, I2C_SMBUS_BLOCK_MAX> blockData;
+ auto getData = [&data](auto fl, auto fi, auto a, auto o, auto l,
+ auto* b) { return getDataTempl(data, fl, fi, a, o, l, b); };
+
+ EXPECT_TRUE(findFRUHeader(0, 0, 0, getData, "error", blockData, offset));
+ EXPECT_EQ(0, offset);
+}
+
+TEST(FindFRUHeaderTest, TyanInvalidHeader)
+{
+ std::vector<uint8_t> data = {'$', 'T', 'Y', 'A', 'N', '$', 0, 0};
+ data.resize(0x6000 + I2C_SMBUS_BLOCK_MAX);
+ uint16_t offset = 0;
+ std::array<uint8_t, I2C_SMBUS_BLOCK_MAX> blockData;
+ auto getData = [&data](auto fl, auto fi, auto a, auto o, auto l,
+ auto* b) { return getDataTempl(data, fl, fi, a, o, l, b); };
+
+ EXPECT_FALSE(findFRUHeader(0, 0, 0, getData, "error", blockData, offset));
+}
+
+TEST(FindFRUHeaderTest, TyanNoData)
+{
+ const std::vector<uint8_t> data = {'$', 'T', 'Y', 'A', 'N', '$', 0, 0};
+ uint16_t offset = 0;
+ std::array<uint8_t, I2C_SMBUS_BLOCK_MAX> blockData;
+ auto getData = [&data](auto fl, auto fi, auto a, auto o, auto l,
+ auto* b) { return getDataTempl(data, fl, fi, a, o, l, b); };
+
+ EXPECT_FALSE(findFRUHeader(0, 0, 0, getData, "error", blockData, offset));
+}
+
+TEST(FindFRUHeaderTest, TyanValidHeader)
+{
+ std::vector<uint8_t> data = {'$', 'T', 'Y', 'A', 'N', '$', 0, 0};
+ data.resize(0x6000);
+ constexpr std::array<uint8_t, I2C_SMBUS_BLOCK_MAX> fruHeader = {
+ 0x01, 0x00, 0x01, 0x02, 0x03, 0x04, 0x00, 0xf5};
+ copy(fruHeader.begin(), fruHeader.end(), back_inserter(data));
+
+ uint16_t offset = 0;
+ std::array<uint8_t, I2C_SMBUS_BLOCK_MAX> blockData;
+ auto getData = [&data](auto fl, auto fi, auto a, auto o, auto l,
+ auto* b) { return getDataTempl(data, fl, fi, a, o, l, b); };
+
+ EXPECT_TRUE(findFRUHeader(0, 0, 0, getData, "error", blockData, offset));
+ EXPECT_EQ(0x6000, offset);
+}