Correction of VPD using ECC
ECC algorithm corrects VPD data in 32:1 bit ratio in the
event of corruption.
Main Test Cases:
1) Check correction of KW in records.
2) Check correction while writing and reading VPD.
3) Check for Module VPD correction.
Signed-off-by: Giridhari Krishna <giridharikrishnan@gmail.com>
Change-Id: I48a3db18df9d3a2aecde814610ab1b357e6f310d
diff --git a/app.cpp b/app.cpp
index 07dbb45..63290de 100644
--- a/app.cpp
+++ b/app.cpp
@@ -48,7 +48,9 @@
std::istreambuf_iterator<char>());
// Parse VPD
- IpzVpdParser ipzParser(std::move(vpd), std::string{});
+ uint32_t vpdStartOffset = 0;
+ IpzVpdParser ipzParser(std::move(vpd), std::string{}, file,
+ vpdStartOffset);
auto vpdStore = std::move(std::get<Store>(ipzParser.parse()));
if (doDump)
diff --git a/ibm_vpd_app.cpp b/ibm_vpd_app.cpp
index 367f8d2..57109b6 100644
--- a/ibm_vpd_app.cpp
+++ b/ibm_vpd_app.cpp
@@ -1460,9 +1460,18 @@
try
{
+ uint32_t vpdStartOffset = 0;
+ for (const auto& item : js["frus"][file])
+ {
+ if (item.find("offset") != item.end())
+ {
+ vpdStartOffset = item["offset"];
+ }
+ }
vpdVector = getVpdDataInVector(js, file);
ParserInterface* parser = ParserFactory::getParser(
- vpdVector, (pimPath + baseFruInventoryPath));
+ vpdVector, (pimPath + baseFruInventoryPath), file,
+ vpdStartOffset);
variant<KeywordVpdMap, Store> parseResult;
parseResult = parser->parse();
diff --git a/impl.cpp b/impl.cpp
index a8bd694..7d51433 100644
--- a/impl.cpp
+++ b/impl.cpp
@@ -74,7 +74,7 @@
}
#ifdef IPZ_PARSER
-int Impl::vhdrEccCheck() const
+int Impl::vhdrEccCheck()
{
int rc = eccStatus::SUCCESS;
auto vpdPtr = vpd.cbegin();
@@ -84,8 +84,32 @@
lengths::VHDR_RECORD_LENGTH,
const_cast<uint8_t*>(&vpdPtr[offsets::VHDR_ECC]),
lengths::VHDR_ECC_LENGTH);
-
- if (l_status != VPD_ECC_OK)
+ if (l_status == VPD_ECC_CORRECTABLE_DATA)
+ {
+ try
+ {
+ if (vpdFileStream.is_open())
+ {
+ vpdFileStream.seekp(vpdStartOffset + offsets::VHDR_RECORD,
+ std::ios::beg);
+ vpdFileStream.write(
+ reinterpret_cast<const char*>(&vpd[offsets::VHDR_RECORD]),
+ lengths::VHDR_RECORD_LENGTH);
+ }
+ else
+ {
+ std::cerr << "File not open";
+ rc = eccStatus::FAILED;
+ }
+ }
+ catch (const std::fstream::failure& e)
+ {
+ std::cout << "Error while operating on file with exception:"
+ << e.what();
+ rc = eccStatus::FAILED;
+ }
+ }
+ else if (l_status != VPD_ECC_OK)
{
rc = eccStatus::FAILED;
}
@@ -93,7 +117,7 @@
return rc;
}
-int Impl::vtocEccCheck() const
+int Impl::vtocEccCheck()
{
int rc = eccStatus::SUCCESS;
// Use another pointer to get ECC information from VHDR,
@@ -122,8 +146,31 @@
auto l_status = vpdecc_check_data(
const_cast<uint8_t*>(&vpdPtr[vtocOffset]), vtocLength,
const_cast<uint8_t*>(&vpdPtr[vtocECCOffset]), vtocECCLength);
-
- if (l_status != VPD_ECC_OK)
+ if (l_status == VPD_ECC_CORRECTABLE_DATA)
+ {
+ try
+ {
+ if (vpdFileStream.is_open())
+ {
+ vpdFileStream.seekp(vpdStartOffset + vtocOffset, std::ios::beg);
+ vpdFileStream.write(
+ reinterpret_cast<const char*>(&vpdPtr[vtocOffset]),
+ vtocLength);
+ }
+ else
+ {
+ std::cerr << "File not open";
+ rc = eccStatus::FAILED;
+ }
+ }
+ catch (const std::fstream::failure& e)
+ {
+ std::cout << "Error while operating on file with exception "
+ << e.what();
+ rc = eccStatus::FAILED;
+ }
+ }
+ else if (l_status != VPD_ECC_OK)
{
rc = eccStatus::FAILED;
}
@@ -131,7 +178,7 @@
return rc;
}
-int Impl::recordEccCheck(Binary::const_iterator iterator) const
+int Impl::recordEccCheck(Binary::const_iterator iterator)
{
int rc = eccStatus::SUCCESS;
@@ -163,7 +210,32 @@
auto l_status = vpdecc_check_data(
const_cast<uint8_t*>(&vpdPtr[recordOffset]), recordLength,
const_cast<uint8_t*>(&vpdPtr[eccOffset]), eccLength);
- if (l_status != VPD_ECC_OK)
+ if (l_status == VPD_ECC_CORRECTABLE_DATA)
+ {
+ try
+ {
+ if (vpdFileStream.is_open())
+ {
+ vpdFileStream.seekp(vpdStartOffset + recordOffset,
+ std::ios::beg);
+ vpdFileStream.write(
+ reinterpret_cast<const char*>(&vpdPtr[recordOffset]),
+ recordLength);
+ }
+ else
+ {
+ std::cerr << "File not open";
+ rc = eccStatus::FAILED;
+ }
+ }
+ catch (const std::fstream::failure& e)
+ {
+ std::cout << "Error while operating on file with exception "
+ << e.what();
+ rc = eccStatus::FAILED;
+ }
+ }
+ else if (l_status != VPD_ECC_OK)
{
rc = eccStatus::FAILED;
}
@@ -172,7 +244,7 @@
}
#endif
-void Impl::checkHeader() const
+void Impl::checkHeader()
{
if (vpd.empty() || (lengths::RECORD_MIN > vpd.size()))
{
@@ -201,7 +273,7 @@
}
}
-std::size_t Impl::readTOC(Binary::const_iterator& iterator) const
+std::size_t Impl::readTOC(Binary::const_iterator& iterator)
{
// The offset to VTOC could be 1 or 2 bytes long
RecordOffset vtocOffset = getVtocOffset();
@@ -244,7 +316,7 @@
}
internal::OffsetList Impl::readPT(Binary::const_iterator iterator,
- std::size_t ptLength) const
+ std::size_t ptLength)
{
internal::OffsetList offsets{};
diff --git a/impl.hpp b/impl.hpp
index 58cb674..738549a 100644
--- a/impl.hpp
+++ b/impl.hpp
@@ -4,6 +4,7 @@
#include "store.hpp"
#include <cstddef>
+#include <fstream>
namespace openpower
{
@@ -68,10 +69,24 @@
*
* @param[in] vpdBuffer - Binary VPD
* @param[in] path - To call out FRU in case of any PEL.
+ * @param[in] vpdFilePath - VPD File Path
+ * @param[in] vpdStartOffset - Start offset of VPD.
*/
- Impl(const Binary& vpdBuffer, const std::string& path) :
- vpd(vpdBuffer), inventoryPath(path), out{}
+ Impl(const Binary& vpdBuffer, const std::string& path,
+ const std::string& vpdFilePath, uint32_t vpdStartOffset) :
+ vpd(vpdBuffer),
+ inventoryPath(path), vpdFilePath(vpdFilePath),
+ vpdStartOffset(vpdStartOffset), out{}
{
+ try
+ {
+ vpdFileStream.open(vpdFilePath,
+ std::ios::in | std::ios::out | std::ios::binary);
+ }
+ catch (const std::fstream::failure& e)
+ {
+ std::cout << e.what();
+ }
}
/** @brief Run the parser on binary VPD
@@ -99,7 +114,7 @@
* @param[in] iterator - iterator to buffer containing VPD
* @returns Size of the PT keyword in VTOC
*/
- std::size_t readTOC(Binary::const_iterator& iterator) const;
+ std::size_t readTOC(Binary::const_iterator& iterator);
/** @brief Read the PT keyword contained in the VHDR record,
* to obtain offsets to other records in the VPD.
@@ -110,7 +125,7 @@
* @returns List of offsets to records in VPD
*/
internal::OffsetList readPT(Binary::const_iterator iterator,
- std::size_t ptLen) const;
+ std::size_t ptLen);
/** @brief Read VPD information contained within a record
*
@@ -143,24 +158,24 @@
internal::KeywordMap readKeywords(Binary::const_iterator iterator);
/** @brief Checks if the VHDR record is present in the VPD */
- void checkHeader() const;
+ void checkHeader();
/** @brief Checks the ECC for VHDR Record.
* @returns Success(0) OR corrupted data(-1)
*/
- int vhdrEccCheck() const;
+ int vhdrEccCheck();
/** @brief Checks the ECC for VTOC Record.
* @returns Success(0) OR corrupted data(-1)
*/
- int vtocEccCheck() const;
+ int vtocEccCheck();
/** @brief Checks the ECC for the given record.
*
* @param[in] iterator - iterator pointing to a record in the VPD
* @returns Success(0) OR corrupted data(-1)
*/
- int recordEccCheck(Binary::const_iterator iterator) const;
+ int recordEccCheck(Binary::const_iterator iterator);
/** @brief This interface collects Offset of VTOC
* @returns VTOC Offset
@@ -173,6 +188,15 @@
/** Inventory path to call out FRU if required */
const std::string inventoryPath;
+ /** Eeprom hardware path */
+ inventory::Path vpdFilePath;
+
+ /** VPD Offset **/
+ uint32_t vpdStartOffset;
+
+ /** File stream for VPD */
+ std::fstream vpdFileStream;
+
/** @brief parser output */
Parsed out;
};
diff --git a/test/ipz_parser/parser.cpp b/test/ipz_parser/parser.cpp
index 945467a..c4c7566 100644
--- a/test/ipz_parser/parser.cpp
+++ b/test/ipz_parser/parser.cpp
@@ -1,6 +1,7 @@
#include "ipz_parser.hpp"
#include <cassert>
+#include <const.hpp>
#include <defines.hpp>
#include <fstream>
#include <impl.hpp>
@@ -10,6 +11,9 @@
#include <gtest/gtest.h>
using namespace openpower::vpd;
+using namespace openpower::vpd::constants;
+
+constexpr uint32_t vpdOffset = 0;
TEST(IpzVpdParserApp, vpdGoodPath)
{
@@ -37,7 +41,7 @@
0x00, 0x52, 0x54, 0x04};
// call app for this vpd
- parser::Impl p(std::move(vpd), std::string{});
+ parser::Impl p(std::move(vpd), std::string{}, systemVpdFilePath, vpdOffset);
Store vpdStore = p.run();
static const std::string record = "VINI";
@@ -65,7 +69,7 @@
Binary vpd = {};
// VPD is empty
- parser::Impl p(std::move(vpd), std::string{});
+ parser::Impl p(std::move(vpd), std::string{}, systemVpdFilePath, vpdOffset);
// Expecting a throw here
EXPECT_THROW(p.run(), std::runtime_error);
@@ -98,7 +102,7 @@
// corrupt the VHDR
vpd[17] = 0x00;
- parser::Impl p(std::move(vpd), std::string{});
+ parser::Impl p(std::move(vpd), std::string{}, systemVpdFilePath, vpdOffset);
// Expecting a throw here
EXPECT_THROW(p.run(), std::runtime_error);
@@ -131,7 +135,7 @@
// corrupt the VTOC
vpd[61] = 0x00;
- parser::Impl p(std::move(vpd), std::string{});
+ parser::Impl p(std::move(vpd), std::string{}, systemVpdFilePath, vpdOffset);
// Expecting a throw here
EXPECT_THROW(p.run(), std::runtime_error);
diff --git a/vpd-manager/editor_impl.cpp b/vpd-manager/editor_impl.cpp
index 4d81278..426dd7b 100644
--- a/vpd-manager/editor_impl.cpp
+++ b/vpd-manager/editor_impl.cpp
@@ -214,6 +214,18 @@
return lowByte;
}
+void EditorImpl::checkRecordData()
+{
+ auto itrToRecordData = vpdFile.cbegin();
+ std::advance(itrToRecordData, thisRecord.recOffset);
+
+ auto itrToRecordECC = vpdFile.cbegin();
+ std::advance(itrToRecordECC, thisRecord.recECCoffset);
+
+ checkECC(itrToRecordData, itrToRecordECC, thisRecord.recSize,
+ thisRecord.recECCLength);
+}
+
void EditorImpl::checkECC(Binary::const_iterator& itrToRecData,
Binary::const_iterator& itrToECCData,
RecordLength recLength, ECCLength eccLength)
@@ -222,9 +234,33 @@
vpdecc_check_data(const_cast<uint8_t*>(&itrToRecData[0]), recLength,
const_cast<uint8_t*>(&itrToECCData[0]), eccLength);
- if (l_status != VPD_ECC_OK)
+ if (l_status == VPD_ECC_CORRECTABLE_DATA)
{
- throw std::runtime_error("Ecc check failed for VTOC");
+ try
+ {
+ if (vpdFileStream.is_open())
+ {
+ vpdFileStream.seekp(startOffset + thisRecord.recOffset,
+ std::ios::beg);
+ auto end = itrToRecData;
+ std::advance(end, recLength);
+ std::copy(itrToRecData, end,
+ std::ostreambuf_iterator<char>(vpdFileStream));
+ }
+ else
+ {
+ throw std::runtime_error("Ecc correction failed");
+ }
+ }
+ catch (const std::fstream::failure& e)
+ {
+ std::cout << "Error while operating on file with exception";
+ throw std::runtime_error("Ecc correction failed");
+ }
+ }
+ else if (l_status != VPD_ECC_OK)
+ {
+ throw std::runtime_error("Ecc check failed");
}
}
@@ -600,8 +636,8 @@
if (vpdType == KW_VAL_PAIR_START_TAG)
{
// objPath should be empty only in case of test run.
- ParserInterface* Iparser =
- ParserFactory::getParser(completeVPDFile, objPath);
+ ParserInterface* Iparser = ParserFactory::getParser(
+ completeVPDFile, objPath, vpdFilePath, startOffset);
IpzVpdParser* ipzParser = dynamic_cast<IpzVpdParser*>(Iparser);
try
@@ -622,6 +658,9 @@
// check record for keywrod
checkRecordForKwd();
+ // Check Data before updating
+ checkRecordData();
+
// update the data to the file
updateData(kwdData);
diff --git a/vpd-manager/editor_impl.hpp b/vpd-manager/editor_impl.hpp
index d10e157..5beedba 100644
--- a/vpd-manager/editor_impl.hpp
+++ b/vpd-manager/editor_impl.hpp
@@ -171,6 +171,9 @@
void makeDbusCall(const std::string& object, const std::string& interface,
const std::string& property, const std::variant<T>& data);
+ /** @brief Method to check the record's Data using ECC */
+ void checkRecordData();
+
// path to the VPD file to edit
inventory::Path vpdFilePath;
@@ -180,6 +183,9 @@
// stream to perform operation on file
std::fstream vpdFileStream;
+ // stream to operate on VPD data
+ std::fstream vpdDataFileStream;
+
// offset to get vpd data from EEPROM
uint32_t startOffset;
diff --git a/vpd-manager/manager.cpp b/vpd-manager/manager.cpp
index 53c9ad8..5fc415e 100644
--- a/vpd-manager/manager.cpp
+++ b/vpd-manager/manager.cpp
@@ -168,11 +168,13 @@
try
{
auto vpdVector = getVpdDataInVector(jsonFile, systemVpdFilePath);
+ uint32_t vpdStartOffset = 0;
const auto& inventoryPath =
jsonFile["frus"][systemVpdFilePath][0]["inventoryPath"]
.get_ref<const nlohmann::json::string_t&>();
- parser = ParserFactory::getParser(vpdVector, (pimPath + inventoryPath));
+ parser = ParserFactory::getParser(vpdVector, (pimPath + inventoryPath),
+ systemVpdFilePath, vpdStartOffset);
auto parseResult = parser->parse();
if (auto pVal = std::get_if<Store>(&parseResult))
diff --git a/vpd-parser/ipz_parser.cpp b/vpd-parser/ipz_parser.cpp
index 4f2b30e..d923aa6 100644
--- a/vpd-parser/ipz_parser.cpp
+++ b/vpd-parser/ipz_parser.cpp
@@ -15,14 +15,14 @@
std::variant<kwdVpdMap, Store> IpzVpdParser::parse()
{
- Impl p(vpd, inventoryPath);
+ Impl p(vpd, inventoryPath, vpdFilePath, vpdStartOffset);
Store s = p.run();
return s;
}
void IpzVpdParser::processHeader()
{
- Impl p(vpd, inventoryPath);
+ Impl p(vpd, inventoryPath, vpdFilePath, vpdStartOffset);
p.checkVPDHeader();
}
@@ -34,4 +34,4 @@
} // namespace parser
} // namespace ipz
} // namespace vpd
-} // namespace openpower
+} // namespace openpower
\ No newline at end of file
diff --git a/vpd-parser/ipz_parser.hpp b/vpd-parser/ipz_parser.hpp
index 5a0865c..e431cd3 100644
--- a/vpd-parser/ipz_parser.hpp
+++ b/vpd-parser/ipz_parser.hpp
@@ -31,9 +31,16 @@
/**
* @brief Constructor
+ * @param[in] - VpdVector - vpd buffer
+ * @param[in] - path - Inventory Path
+ * @param[in] - vpdFilePath - VPD H/w path
+ * @param[in] - vpdStartOffset - VPD starting offset
*/
- IpzVpdParser(const Binary& VpdVector, const std::string& path) :
- vpd(VpdVector), inventoryPath(path)
+ IpzVpdParser(const Binary& VpdVector, const std::string& path,
+ const std::string& vpdFilePath, uint32_t vpdStartOffset) :
+ vpd(VpdVector),
+ inventoryPath(path), vpdFilePath(vpdFilePath),
+ vpdStartOffset(vpdStartOffset)
{
}
@@ -63,6 +70,13 @@
/*Inventory path of the FRU */
const std::string inventoryPath;
+
+ /* VPD Path */
+ const std::string vpdFilePath;
+
+ /* Offset */
+ uint32_t vpdStartOffset;
+
}; // class IpzVpdParser
} // namespace parser
diff --git a/vpd-parser/parser_factory.cpp b/vpd-parser/parser_factory.cpp
index 1afe96a..04d4960 100644
--- a/vpd-parser/parser_factory.cpp
+++ b/vpd-parser/parser_factory.cpp
@@ -24,9 +24,9 @@
{
namespace factory
{
-interface::ParserInterface*
- ParserFactory::getParser(const Binary& vpdVector,
- const std::string& inventoryPath)
+interface::ParserInterface* ParserFactory::getParser(
+ const Binary& vpdVector, const std::string& inventoryPath,
+ const std::string& vpdFilePath, uint32_t vpdStartOffset)
{
vpdType type = vpdTypeCheck(vpdVector);
@@ -34,7 +34,8 @@
{
case IPZ_VPD:
{
- return new IpzVpdParser(vpdVector, inventoryPath);
+ return new IpzVpdParser(vpdVector, inventoryPath, vpdFilePath,
+ vpdStartOffset);
}
case KEYWORD_VPD:
diff --git a/vpd-parser/parser_factory.hpp b/vpd-parser/parser_factory.hpp
index 97a96b8..983b8fd 100644
--- a/vpd-parser/parser_factory.hpp
+++ b/vpd-parser/parser_factory.hpp
@@ -31,10 +31,13 @@
* @brief A method to get object of concrete parser class.
* @param[in] - vpd file to check for the type.
* @param[in] - InventoryPath to call out FRU in case PEL is logged.
+ * @param[in] - vpdFilePath for VPD HW path.
+ * @param[in] - vpdStartOffset for starting offset of VPD.
* @return - Pointer to concrete parser class object.
*/
static interface::ParserInterface*
- getParser(const Binary& vpdVector, const std::string& inventoryPath);
+ getParser(const Binary& vpdVector, const std::string& inventoryPath,
+ const std::string& vpdFilePath, uint32_t vpdStartOffset);
/**
* @brief A method to delete the parser object.
diff --git a/vpd_tool_impl.cpp b/vpd_tool_impl.cpp
index 3926c75..753181d 100644
--- a/vpd_tool_impl.cpp
+++ b/vpd_tool_impl.cpp
@@ -50,8 +50,10 @@
Binary vpdVector{};
+ uint32_t vpdStartOffset = 0;
vpdVector = getVpdDataInVector(js, constants::systemVpdFilePath);
- ParserInterface* parser = ParserFactory::getParser(vpdVector, invPath);
+ ParserInterface* parser = ParserFactory::getParser(
+ vpdVector, invPath, constants::systemVpdFilePath, vpdStartOffset);
auto parseResult = parser->parse();
ParserFactory::freeParser(parser);
@@ -579,7 +581,17 @@
const std::string& inventoryPath =
jsonFile["frus"][fruPath][0]["inventoryPath"];
- Impl obj(completeVPDFile, (constants::pimPath + inventoryPath));
+ uint32_t vpdStartOffset = 0;
+ for (const auto& item : jsonFile["frus"][fruPath])
+ {
+ if (item.find("offset") != item.end())
+ {
+ vpdStartOffset = item["offset"];
+ }
+ }
+
+ Impl obj(completeVPDFile, (constants::pimPath + inventoryPath), fruPath,
+ vpdStartOffset);
std::string keywordVal = obj.readKwFromHw(recordName, keyword);
if (!keywordVal.empty())
@@ -1034,4 +1046,4 @@
<< "\nManufacturing reset on system vpd keywords is unsuccessful";
}
return 0;
-}
\ No newline at end of file
+}