xref: /openbmc/openpower-vpd-parser/vpd-manager/src/ipz_parser.cpp (revision 43fedabc032ba7c209b58111b6c35c7d95a9f14e)
1fa5e4d32SSunny Srivastava #include "config.h"
2fa5e4d32SSunny Srivastava 
3fa5e4d32SSunny Srivastava #include "ipz_parser.hpp"
4fa5e4d32SSunny Srivastava 
5fa5e4d32SSunny Srivastava #include "vpdecc/vpdecc.h"
6fa5e4d32SSunny Srivastava 
7fa5e4d32SSunny Srivastava #include "constants.hpp"
8fa5e4d32SSunny Srivastava #include "exceptions.hpp"
9fa5e4d32SSunny Srivastava 
10fa5e4d32SSunny Srivastava #include <nlohmann/json.hpp>
11fa5e4d32SSunny Srivastava 
12fa5e4d32SSunny Srivastava #include <typeindex>
13fa5e4d32SSunny Srivastava 
14fa5e4d32SSunny Srivastava namespace vpd
15fa5e4d32SSunny Srivastava {
16fa5e4d32SSunny Srivastava 
17fa5e4d32SSunny Srivastava // Offset of different entries in VPD data.
18fa5e4d32SSunny Srivastava enum Offset
19fa5e4d32SSunny Srivastava {
20fa5e4d32SSunny Srivastava     VHDR = 17,
21fa5e4d32SSunny Srivastava     VHDR_TOC_ENTRY = 29,
22fa5e4d32SSunny Srivastava     VTOC_PTR = 35,
23fa5e4d32SSunny Srivastava     VTOC_REC_LEN = 37,
24fa5e4d32SSunny Srivastava     VTOC_ECC_OFF = 39,
25fa5e4d32SSunny Srivastava     VTOC_ECC_LEN = 41,
26fa5e4d32SSunny Srivastava     VTOC_DATA = 13,
27fa5e4d32SSunny Srivastava     VHDR_ECC = 0,
28fa5e4d32SSunny Srivastava     VHDR_RECORD = 11
29fa5e4d32SSunny Srivastava };
30fa5e4d32SSunny Srivastava 
31fa5e4d32SSunny Srivastava // Length of some specific entries w.r.t VPD data.
32fa5e4d32SSunny Srivastava enum Length
33fa5e4d32SSunny Srivastava {
34fa5e4d32SSunny Srivastava     RECORD_NAME = 4,
35fa5e4d32SSunny Srivastava     KW_NAME = 2,
36fa5e4d32SSunny Srivastava     RECORD_OFFSET = 2,
37fa5e4d32SSunny Srivastava     RECORD_MIN = 44,
38fa5e4d32SSunny Srivastava     RECORD_LENGTH = 2,
39fa5e4d32SSunny Srivastava     RECORD_ECC_OFFSET = 2,
40fa5e4d32SSunny Srivastava     VHDR_ECC_LENGTH = 11,
41fa5e4d32SSunny Srivastava     VHDR_RECORD_LENGTH = 44,
42fa5e4d32SSunny Srivastava     RECORD_TYPE = 2,
43fa5e4d32SSunny Srivastava     SKIP_A_RECORD_IN_PT = 14,
44fa5e4d32SSunny Srivastava     JUMP_TO_RECORD_NAME = 6
45fa5e4d32SSunny Srivastava }; // enum Length
46fa5e4d32SSunny Srivastava 
47fa5e4d32SSunny Srivastava /**
48fa5e4d32SSunny Srivastava  * @brief API to read 2 bytes LE data.
49fa5e4d32SSunny Srivastava  *
50fa5e4d32SSunny Srivastava  * @param[in] iterator - iterator to VPD vector.
51fa5e4d32SSunny Srivastava  * @return read bytes.
52fa5e4d32SSunny Srivastava  */
readUInt16LE(types::BinaryVector::const_iterator iterator)53fa5e4d32SSunny Srivastava static uint16_t readUInt16LE(types::BinaryVector::const_iterator iterator)
54fa5e4d32SSunny Srivastava {
55fa5e4d32SSunny Srivastava     uint16_t lowByte = *iterator;
56fa5e4d32SSunny Srivastava     uint16_t highByte = *(iterator + 1);
57fa5e4d32SSunny Srivastava     lowByte |= (highByte << 8);
58fa5e4d32SSunny Srivastava     return lowByte;
59fa5e4d32SSunny Srivastava }
60fa5e4d32SSunny Srivastava 
vhdrEccCheck()61fa5e4d32SSunny Srivastava bool IpzVpdParser::vhdrEccCheck()
62fa5e4d32SSunny Srivastava {
63fa5e4d32SSunny Srivastava     auto vpdPtr = m_vpdVector.cbegin();
64fa5e4d32SSunny Srivastava 
65fa5e4d32SSunny Srivastava     auto l_status = vpdecc_check_data(
66fa5e4d32SSunny Srivastava         const_cast<uint8_t*>(&vpdPtr[Offset::VHDR_RECORD]),
67fa5e4d32SSunny Srivastava         Length::VHDR_RECORD_LENGTH,
68fa5e4d32SSunny Srivastava         const_cast<uint8_t*>(&vpdPtr[Offset::VHDR_ECC]),
69fa5e4d32SSunny Srivastava         Length::VHDR_ECC_LENGTH);
70fa5e4d32SSunny Srivastava     if (l_status == VPD_ECC_CORRECTABLE_DATA)
71fa5e4d32SSunny Srivastava     {
72fa5e4d32SSunny Srivastava         try
73fa5e4d32SSunny Srivastava         {
74fa5e4d32SSunny Srivastava             if (m_vpdFileStream.is_open())
75fa5e4d32SSunny Srivastava             {
76fa5e4d32SSunny Srivastava                 m_vpdFileStream.seekp(m_vpdStartOffset + Offset::VHDR_RECORD,
77fa5e4d32SSunny Srivastava                                       std::ios::beg);
78fa5e4d32SSunny Srivastava                 m_vpdFileStream.write(reinterpret_cast<const char*>(
79fa5e4d32SSunny Srivastava                                           &m_vpdVector[Offset::VHDR_RECORD]),
80fa5e4d32SSunny Srivastava                                       Length::VHDR_RECORD_LENGTH);
81fa5e4d32SSunny Srivastava             }
82fa5e4d32SSunny Srivastava             else
83fa5e4d32SSunny Srivastava             {
84fa5e4d32SSunny Srivastava                 logging::logMessage("File not open");
85fa5e4d32SSunny Srivastava                 return false;
86fa5e4d32SSunny Srivastava             }
87fa5e4d32SSunny Srivastava         }
88fa5e4d32SSunny Srivastava         catch (const std::fstream::failure& e)
89fa5e4d32SSunny Srivastava         {
90fa5e4d32SSunny Srivastava             logging::logMessage(
91fa5e4d32SSunny Srivastava                 "Error while operating on file with exception: " +
92fa5e4d32SSunny Srivastava                 std::string(e.what()));
93fa5e4d32SSunny Srivastava             return false;
94fa5e4d32SSunny Srivastava         }
95fa5e4d32SSunny Srivastava     }
96fa5e4d32SSunny Srivastava     else if (l_status != VPD_ECC_OK)
97fa5e4d32SSunny Srivastava     {
98fa5e4d32SSunny Srivastava         return false;
99fa5e4d32SSunny Srivastava     }
100fa5e4d32SSunny Srivastava 
101fa5e4d32SSunny Srivastava     return true;
102fa5e4d32SSunny Srivastava }
103fa5e4d32SSunny Srivastava 
vtocEccCheck()104fa5e4d32SSunny Srivastava bool IpzVpdParser::vtocEccCheck()
105fa5e4d32SSunny Srivastava {
106fa5e4d32SSunny Srivastava     auto vpdPtr = m_vpdVector.cbegin();
107fa5e4d32SSunny Srivastava 
108fa5e4d32SSunny Srivastava     std::advance(vpdPtr, Offset::VTOC_PTR);
109fa5e4d32SSunny Srivastava 
110fa5e4d32SSunny Srivastava     // The offset to VTOC could be 1 or 2 bytes long
111fa5e4d32SSunny Srivastava     auto vtocOffset = readUInt16LE(vpdPtr);
112fa5e4d32SSunny Srivastava 
113fa5e4d32SSunny Srivastava     // Get the VTOC Length
114fa5e4d32SSunny Srivastava     std::advance(vpdPtr, sizeof(types::RecordOffset));
115fa5e4d32SSunny Srivastava     auto vtocLength = readUInt16LE(vpdPtr);
116fa5e4d32SSunny Srivastava 
117fa5e4d32SSunny Srivastava     // Get the ECC Offset
118fa5e4d32SSunny Srivastava     std::advance(vpdPtr, sizeof(types::RecordLength));
119fa5e4d32SSunny Srivastava     auto vtocECCOffset = readUInt16LE(vpdPtr);
120fa5e4d32SSunny Srivastava 
121fa5e4d32SSunny Srivastava     // Get the ECC length
122fa5e4d32SSunny Srivastava     std::advance(vpdPtr, sizeof(types::ECCOffset));
123fa5e4d32SSunny Srivastava     auto vtocECCLength = readUInt16LE(vpdPtr);
124fa5e4d32SSunny Srivastava 
125fa5e4d32SSunny Srivastava     // Reset pointer to start of the vpd,
126fa5e4d32SSunny Srivastava     // so that Offset will point to correct address
127fa5e4d32SSunny Srivastava     vpdPtr = m_vpdVector.cbegin();
128fa5e4d32SSunny Srivastava     auto l_status = vpdecc_check_data(
129fa5e4d32SSunny Srivastava         const_cast<uint8_t*>(&m_vpdVector[vtocOffset]), vtocLength,
130fa5e4d32SSunny Srivastava         const_cast<uint8_t*>(&m_vpdVector[vtocECCOffset]), vtocECCLength);
131fa5e4d32SSunny Srivastava     if (l_status == VPD_ECC_CORRECTABLE_DATA)
132fa5e4d32SSunny Srivastava     {
133fa5e4d32SSunny Srivastava         try
134fa5e4d32SSunny Srivastava         {
135fa5e4d32SSunny Srivastava             if (m_vpdFileStream.is_open())
136fa5e4d32SSunny Srivastava             {
137fa5e4d32SSunny Srivastava                 m_vpdFileStream.seekp(m_vpdStartOffset + vtocOffset,
138fa5e4d32SSunny Srivastava                                       std::ios::beg);
139fa5e4d32SSunny Srivastava                 m_vpdFileStream.write(
140fa5e4d32SSunny Srivastava                     reinterpret_cast<const char*>(&m_vpdVector[vtocOffset]),
141fa5e4d32SSunny Srivastava                     vtocLength);
142fa5e4d32SSunny Srivastava             }
143fa5e4d32SSunny Srivastava             else
144fa5e4d32SSunny Srivastava             {
145fa5e4d32SSunny Srivastava                 logging::logMessage("File not open");
146fa5e4d32SSunny Srivastava                 return false;
147fa5e4d32SSunny Srivastava             }
148fa5e4d32SSunny Srivastava         }
149fa5e4d32SSunny Srivastava         catch (const std::fstream::failure& e)
150fa5e4d32SSunny Srivastava         {
151fa5e4d32SSunny Srivastava             logging::logMessage(
152fa5e4d32SSunny Srivastava                 "Error while operating on file with exception " +
153fa5e4d32SSunny Srivastava                 std::string(e.what()));
154fa5e4d32SSunny Srivastava             return false;
155fa5e4d32SSunny Srivastava         }
156fa5e4d32SSunny Srivastava     }
157fa5e4d32SSunny Srivastava     else if (l_status != VPD_ECC_OK)
158fa5e4d32SSunny Srivastava     {
159fa5e4d32SSunny Srivastava         return false;
160fa5e4d32SSunny Srivastava     }
161fa5e4d32SSunny Srivastava 
162fa5e4d32SSunny Srivastava     return true;
163fa5e4d32SSunny Srivastava }
164fa5e4d32SSunny Srivastava 
recordEccCheck(types::BinaryVector::const_iterator iterator)165fa5e4d32SSunny Srivastava bool IpzVpdParser::recordEccCheck(types::BinaryVector::const_iterator iterator)
166fa5e4d32SSunny Srivastava {
167fa5e4d32SSunny Srivastava     auto recordOffset = readUInt16LE(iterator);
168fa5e4d32SSunny Srivastava 
169fa5e4d32SSunny Srivastava     std::advance(iterator, sizeof(types::RecordOffset));
170fa5e4d32SSunny Srivastava     auto recordLength = readUInt16LE(iterator);
171fa5e4d32SSunny Srivastava 
172fa5e4d32SSunny Srivastava     if (recordOffset == 0 || recordLength == 0)
173fa5e4d32SSunny Srivastava     {
174fa5e4d32SSunny Srivastava         throw(DataException("Invalid record offset or length"));
175fa5e4d32SSunny Srivastava     }
176fa5e4d32SSunny Srivastava 
177fa5e4d32SSunny Srivastava     std::advance(iterator, sizeof(types::RecordLength));
178fa5e4d32SSunny Srivastava     auto eccOffset = readUInt16LE(iterator);
179fa5e4d32SSunny Srivastava 
180fa5e4d32SSunny Srivastava     std::advance(iterator, sizeof(types::ECCOffset));
181fa5e4d32SSunny Srivastava     auto eccLength = readUInt16LE(iterator);
182fa5e4d32SSunny Srivastava 
183fa5e4d32SSunny Srivastava     if (eccLength == 0 || eccOffset == 0)
184fa5e4d32SSunny Srivastava     {
185fa5e4d32SSunny Srivastava         throw(EccException("Invalid ECC length or offset."));
186fa5e4d32SSunny Srivastava     }
187fa5e4d32SSunny Srivastava 
188fa5e4d32SSunny Srivastava     auto vpdPtr = m_vpdVector.cbegin();
189fa5e4d32SSunny Srivastava 
190fa5e4d32SSunny Srivastava     if (vpdecc_check_data(
191fa5e4d32SSunny Srivastava             const_cast<uint8_t*>(&vpdPtr[recordOffset]), recordLength,
192fa5e4d32SSunny Srivastava             const_cast<uint8_t*>(&vpdPtr[eccOffset]), eccLength) == VPD_ECC_OK)
193fa5e4d32SSunny Srivastava     {
194fa5e4d32SSunny Srivastava         return true;
195fa5e4d32SSunny Srivastava     }
196fa5e4d32SSunny Srivastava 
197fa5e4d32SSunny Srivastava     return false;
198fa5e4d32SSunny Srivastava }
199fa5e4d32SSunny Srivastava 
checkHeader(types::BinaryVector::const_iterator itrToVPD)200fa5e4d32SSunny Srivastava void IpzVpdParser::checkHeader(types::BinaryVector::const_iterator itrToVPD)
201fa5e4d32SSunny Srivastava {
202fa5e4d32SSunny Srivastava     if (m_vpdVector.empty() || (Length::RECORD_MIN > m_vpdVector.size()))
203fa5e4d32SSunny Srivastava     {
204fa5e4d32SSunny Srivastava         throw(DataException("Malformed VPD"));
205fa5e4d32SSunny Srivastava     }
206fa5e4d32SSunny Srivastava 
207fa5e4d32SSunny Srivastava     std::advance(itrToVPD, Offset::VHDR);
208fa5e4d32SSunny Srivastava     auto stop = std::next(itrToVPD, Length::RECORD_NAME);
209fa5e4d32SSunny Srivastava 
210fa5e4d32SSunny Srivastava     std::string record(itrToVPD, stop);
211fa5e4d32SSunny Srivastava     if ("VHDR" != record)
212fa5e4d32SSunny Srivastava     {
213fa5e4d32SSunny Srivastava         throw(DataException("VHDR record not found"));
214fa5e4d32SSunny Srivastava     }
215fa5e4d32SSunny Srivastava 
216fa5e4d32SSunny Srivastava     if (!vhdrEccCheck())
217fa5e4d32SSunny Srivastava     {
218fa5e4d32SSunny Srivastava         throw(EccException("ERROR: VHDR ECC check Failed"));
219fa5e4d32SSunny Srivastava     }
220fa5e4d32SSunny Srivastava }
221fa5e4d32SSunny Srivastava 
readTOC(types::BinaryVector::const_iterator & itrToVPD)222fa5e4d32SSunny Srivastava auto IpzVpdParser::readTOC(types::BinaryVector::const_iterator& itrToVPD)
223fa5e4d32SSunny Srivastava {
224fa5e4d32SSunny Srivastava     // The offset to VTOC could be 1 or 2 bytes long
225fa5e4d32SSunny Srivastava     uint16_t vtocOffset =
226fa5e4d32SSunny Srivastava         readUInt16LE((itrToVPD + Offset::VTOC_PTR)); // itrToVPD);
227fa5e4d32SSunny Srivastava 
228fa5e4d32SSunny Srivastava     // Got the offset to VTOC, skip past record header and keyword header
229fa5e4d32SSunny Srivastava     // to get to the record name.
230fa5e4d32SSunny Srivastava     std::advance(itrToVPD, vtocOffset + sizeof(types::RecordId) +
231fa5e4d32SSunny Srivastava                                sizeof(types::RecordSize) +
232fa5e4d32SSunny Srivastava                                // Skip past the RT keyword, which contains
233fa5e4d32SSunny Srivastava                                // the record name.
234fa5e4d32SSunny Srivastava                                Length::KW_NAME + sizeof(types::KwSize));
235fa5e4d32SSunny Srivastava 
236fa5e4d32SSunny Srivastava     std::string record(itrToVPD, std::next(itrToVPD, Length::RECORD_NAME));
237fa5e4d32SSunny Srivastava     if ("VTOC" != record)
238fa5e4d32SSunny Srivastava     {
239fa5e4d32SSunny Srivastava         throw(DataException("VTOC record not found"));
240fa5e4d32SSunny Srivastava     }
241fa5e4d32SSunny Srivastava 
242fa5e4d32SSunny Srivastava     if (!vtocEccCheck())
243fa5e4d32SSunny Srivastava     {
244fa5e4d32SSunny Srivastava         throw(EccException("ERROR: VTOC ECC check Failed"));
245fa5e4d32SSunny Srivastava     }
246fa5e4d32SSunny Srivastava 
247fa5e4d32SSunny Srivastava     // VTOC record name is good, now read through the TOC, stored in the PT
248fa5e4d32SSunny Srivastava     // PT keyword; vpdBuffer is now pointing at the first character of the
249fa5e4d32SSunny Srivastava     // name 'VTOC', jump to PT data.
250fa5e4d32SSunny Srivastava     // Skip past record name and KW name, 'PT'
251fa5e4d32SSunny Srivastava     std::advance(itrToVPD, Length::RECORD_NAME + Length::KW_NAME);
252fa5e4d32SSunny Srivastava 
253fa5e4d32SSunny Srivastava     // Note size of PT
254fa5e4d32SSunny Srivastava     auto ptLen = *itrToVPD;
255fa5e4d32SSunny Srivastava 
256fa5e4d32SSunny Srivastava     // Skip past PT size
257fa5e4d32SSunny Srivastava     std::advance(itrToVPD, sizeof(types::KwSize));
258fa5e4d32SSunny Srivastava 
259fa5e4d32SSunny Srivastava     // length of PT keyword
260fa5e4d32SSunny Srivastava     return ptLen;
261fa5e4d32SSunny Srivastava }
262fa5e4d32SSunny Srivastava 
readPT(types::BinaryVector::const_iterator & itrToPT,auto ptLength)263fa5e4d32SSunny Srivastava types::RecordOffsetList IpzVpdParser::readPT(
264fa5e4d32SSunny Srivastava     types::BinaryVector::const_iterator& itrToPT, auto ptLength)
265fa5e4d32SSunny Srivastava {
266fa5e4d32SSunny Srivastava     types::RecordOffsetList recordOffsets;
267fa5e4d32SSunny Srivastava 
268fa5e4d32SSunny Srivastava     auto end = itrToPT;
269fa5e4d32SSunny Srivastava     std::advance(end, ptLength);
270fa5e4d32SSunny Srivastava 
271fa5e4d32SSunny Srivastava     // Look at each entry in the PT keyword. In the entry,
272fa5e4d32SSunny Srivastava     // we care only about the record offset information.
273fa5e4d32SSunny Srivastava     while (itrToPT < end)
274fa5e4d32SSunny Srivastava     {
275fa5e4d32SSunny Srivastava         std::string recordName(itrToPT, itrToPT + Length::RECORD_NAME);
276fa5e4d32SSunny Srivastava         // Skip record name and record type
277fa5e4d32SSunny Srivastava         std::advance(itrToPT, Length::RECORD_NAME + sizeof(types::RecordType));
278fa5e4d32SSunny Srivastava 
279fa5e4d32SSunny Srivastava         // Get record offset
280fa5e4d32SSunny Srivastava         recordOffsets.push_back(readUInt16LE(itrToPT));
281fa5e4d32SSunny Srivastava         try
282fa5e4d32SSunny Srivastava         {
283fa5e4d32SSunny Srivastava             // Verify the ECC for this Record
284fa5e4d32SSunny Srivastava             if (!recordEccCheck(itrToPT))
285fa5e4d32SSunny Srivastava             {
286fa5e4d32SSunny Srivastava                 throw(EccException("ERROR: ECC check failed"));
287fa5e4d32SSunny Srivastava             }
288fa5e4d32SSunny Srivastava         }
289fa5e4d32SSunny Srivastava         catch (const EccException& ex)
290fa5e4d32SSunny Srivastava         {
291fa5e4d32SSunny Srivastava             logging::logMessage(ex.what());
292fa5e4d32SSunny Srivastava 
293fa5e4d32SSunny Srivastava             /*TODO: uncomment when PEL code goes in */
294fa5e4d32SSunny Srivastava 
295fa5e4d32SSunny Srivastava             /*std::string errMsg =
296fa5e4d32SSunny Srivastava                 std::string{ex.what()} + " Record: " + recordName;
297fa5e4d32SSunny Srivastava 
298fa5e4d32SSunny Srivastava             inventory::PelAdditionalData additionalData{};
299fa5e4d32SSunny Srivastava             additionalData.emplace("DESCRIPTION", errMsg);
300fa5e4d32SSunny Srivastava             additionalData.emplace("CALLOUT_INVENTORY_PATH", inventoryPath);
301fa5e4d32SSunny Srivastava             createPEL(additionalData, PelSeverity::WARNING,
302fa5e4d32SSunny Srivastava                       errIntfForEccCheckFail, nullptr);*/
303fa5e4d32SSunny Srivastava         }
304fa5e4d32SSunny Srivastava         catch (const DataException& ex)
305fa5e4d32SSunny Srivastava         {
306fa5e4d32SSunny Srivastava             logging::logMessage(ex.what());
307fa5e4d32SSunny Srivastava 
308fa5e4d32SSunny Srivastava             /*TODO: uncomment when PEL code goes in */
309fa5e4d32SSunny Srivastava 
310fa5e4d32SSunny Srivastava             /*std::string errMsg =
311fa5e4d32SSunny Srivastava                 std::string{ex.what()} + " Record: " + recordName;
312fa5e4d32SSunny Srivastava 
313fa5e4d32SSunny Srivastava             inventory::PelAdditionalData additionalData{};
314fa5e4d32SSunny Srivastava             additionalData.emplace("DESCRIPTION", errMsg);
315fa5e4d32SSunny Srivastava             additionalData.emplace("CALLOUT_INVENTORY_PATH", inventoryPath);
316fa5e4d32SSunny Srivastava             createPEL(additionalData, PelSeverity::WARNING,
317fa5e4d32SSunny Srivastava                       errIntfForInvalidVPD, nullptr);*/
318fa5e4d32SSunny Srivastava         }
319fa5e4d32SSunny Srivastava 
320fa5e4d32SSunny Srivastava         // Jump record size, record length, ECC offset and ECC length
321fa5e4d32SSunny Srivastava         std::advance(itrToPT,
322fa5e4d32SSunny Srivastava                      sizeof(types::RecordOffset) + sizeof(types::RecordLength) +
323fa5e4d32SSunny Srivastava                          sizeof(types::ECCOffset) + sizeof(types::ECCLength));
324fa5e4d32SSunny Srivastava     }
325fa5e4d32SSunny Srivastava 
326fa5e4d32SSunny Srivastava     return recordOffsets;
327fa5e4d32SSunny Srivastava }
328fa5e4d32SSunny Srivastava 
readKeywords(types::BinaryVector::const_iterator & itrToKwds)329*43fedabcSPatrick Williams types::IPZVpdMap::mapped_type IpzVpdParser::readKeywords(
330*43fedabcSPatrick Williams     types::BinaryVector::const_iterator& itrToKwds)
331fa5e4d32SSunny Srivastava {
332fa5e4d32SSunny Srivastava     types::IPZVpdMap::mapped_type kwdValueMap{};
333fa5e4d32SSunny Srivastava     while (true)
334fa5e4d32SSunny Srivastava     {
335fa5e4d32SSunny Srivastava         // Note keyword name
336fa5e4d32SSunny Srivastava         std::string kwdName(itrToKwds, itrToKwds + Length::KW_NAME);
337fa5e4d32SSunny Srivastava         if (constants::LAST_KW == kwdName)
338fa5e4d32SSunny Srivastava         {
339fa5e4d32SSunny Srivastava             // We're done
340fa5e4d32SSunny Srivastava             break;
341fa5e4d32SSunny Srivastava         }
342fa5e4d32SSunny Srivastava         // Check if the Keyword is '#kw'
343fa5e4d32SSunny Srivastava         char kwNameStart = *itrToKwds;
344fa5e4d32SSunny Srivastava 
345fa5e4d32SSunny Srivastava         // Jump past keyword name
346fa5e4d32SSunny Srivastava         std::advance(itrToKwds, Length::KW_NAME);
347fa5e4d32SSunny Srivastava 
348fa5e4d32SSunny Srivastava         std::size_t kwdDataLength;
349fa5e4d32SSunny Srivastava         std::size_t lengthHighByte;
350fa5e4d32SSunny Srivastava 
351fa5e4d32SSunny Srivastava         if (constants::POUND_KW == kwNameStart)
352fa5e4d32SSunny Srivastava         {
353fa5e4d32SSunny Srivastava             // Note keyword data length
354fa5e4d32SSunny Srivastava             kwdDataLength = *itrToKwds;
355fa5e4d32SSunny Srivastava             lengthHighByte = *(itrToKwds + 1);
356fa5e4d32SSunny Srivastava             kwdDataLength |= (lengthHighByte << 8);
357fa5e4d32SSunny Srivastava 
358fa5e4d32SSunny Srivastava             // Jump past 2Byte keyword length
359fa5e4d32SSunny Srivastava             std::advance(itrToKwds, sizeof(types::PoundKwSize));
360fa5e4d32SSunny Srivastava         }
361fa5e4d32SSunny Srivastava         else
362fa5e4d32SSunny Srivastava         {
363fa5e4d32SSunny Srivastava             // Note keyword data length
364fa5e4d32SSunny Srivastava             kwdDataLength = *itrToKwds;
365fa5e4d32SSunny Srivastava 
366fa5e4d32SSunny Srivastava             // Jump past keyword length
367fa5e4d32SSunny Srivastava             std::advance(itrToKwds, sizeof(types::KwSize));
368fa5e4d32SSunny Srivastava         }
369fa5e4d32SSunny Srivastava 
370fa5e4d32SSunny Srivastava         // support all the Keywords
371fa5e4d32SSunny Srivastava         auto stop = std::next(itrToKwds, kwdDataLength);
372fa5e4d32SSunny Srivastava         std::string kwdata(itrToKwds, stop);
373fa5e4d32SSunny Srivastava         kwdValueMap.emplace(std::move(kwdName), std::move(kwdata));
374fa5e4d32SSunny Srivastava 
375fa5e4d32SSunny Srivastava         // Jump past keyword data length
376fa5e4d32SSunny Srivastava         std::advance(itrToKwds, kwdDataLength);
377fa5e4d32SSunny Srivastava     }
378fa5e4d32SSunny Srivastava 
379fa5e4d32SSunny Srivastava     return kwdValueMap;
380fa5e4d32SSunny Srivastava }
381fa5e4d32SSunny Srivastava 
processRecord(auto recordOffset)382fa5e4d32SSunny Srivastava void IpzVpdParser::processRecord(auto recordOffset)
383fa5e4d32SSunny Srivastava {
384fa5e4d32SSunny Srivastava     // Jump to record name
385fa5e4d32SSunny Srivastava     auto recordNameOffset =
386fa5e4d32SSunny Srivastava         recordOffset + sizeof(types::RecordId) + sizeof(types::RecordSize) +
387fa5e4d32SSunny Srivastava         // Skip past the RT keyword, which contains
388fa5e4d32SSunny Srivastava         // the record name.
389fa5e4d32SSunny Srivastava         Length::KW_NAME + sizeof(types::KwSize);
390fa5e4d32SSunny Srivastava 
391fa5e4d32SSunny Srivastava     // Get record name
392fa5e4d32SSunny Srivastava     auto itrToVPDStart = m_vpdVector.cbegin();
393fa5e4d32SSunny Srivastava     std::advance(itrToVPDStart, recordNameOffset);
394fa5e4d32SSunny Srivastava 
395fa5e4d32SSunny Srivastava     std::string recordName(itrToVPDStart, itrToVPDStart + Length::RECORD_NAME);
396fa5e4d32SSunny Srivastava 
397fa5e4d32SSunny Srivastava     // proceed to find contained keywords and their values.
398fa5e4d32SSunny Srivastava     std::advance(itrToVPDStart, Length::RECORD_NAME);
399fa5e4d32SSunny Srivastava 
400fa5e4d32SSunny Srivastava     // Reverse back to RT Kw, in ipz vpd, to Read RT KW & value
401fa5e4d32SSunny Srivastava     std::advance(itrToVPDStart, -(Length::KW_NAME + sizeof(types::KwSize) +
402fa5e4d32SSunny Srivastava                                   Length::RECORD_NAME));
403fa5e4d32SSunny Srivastava 
404fa5e4d32SSunny Srivastava     // Add entry for this record (and contained keyword:value pairs)
405fa5e4d32SSunny Srivastava     // to the parsed vpd output.
406fa5e4d32SSunny Srivastava     m_parsedVPDMap.emplace(std::move(recordName),
407fa5e4d32SSunny Srivastava                            std::move(readKeywords(itrToVPDStart)));
408fa5e4d32SSunny Srivastava }
409fa5e4d32SSunny Srivastava 
parse()410fa5e4d32SSunny Srivastava types::VPDMapVariant IpzVpdParser::parse()
411fa5e4d32SSunny Srivastava {
412fa5e4d32SSunny Srivastava     try
413fa5e4d32SSunny Srivastava     {
414fa5e4d32SSunny Srivastava         auto itrToVPD = m_vpdVector.cbegin();
415fa5e4d32SSunny Srivastava 
416fa5e4d32SSunny Srivastava         // Check vaidity of VHDR record
417fa5e4d32SSunny Srivastava         checkHeader(itrToVPD);
418fa5e4d32SSunny Srivastava 
419fa5e4d32SSunny Srivastava         // Read the table of contents
420fa5e4d32SSunny Srivastava         auto ptLen = readTOC(itrToVPD);
421fa5e4d32SSunny Srivastava 
422fa5e4d32SSunny Srivastava         // Read the table of contents record, to get offsets
423fa5e4d32SSunny Srivastava         // to other records.
424fa5e4d32SSunny Srivastava         auto recordOffsets = readPT(itrToVPD, ptLen);
425fa5e4d32SSunny Srivastava         for (const auto& offset : recordOffsets)
426fa5e4d32SSunny Srivastava         {
427fa5e4d32SSunny Srivastava             processRecord(offset);
428fa5e4d32SSunny Srivastava         }
429fa5e4d32SSunny Srivastava 
430fa5e4d32SSunny Srivastava         return m_parsedVPDMap;
431fa5e4d32SSunny Srivastava     }
432fa5e4d32SSunny Srivastava     catch (const std::exception& e)
433fa5e4d32SSunny Srivastava     {
434fa5e4d32SSunny Srivastava         logging::logMessage(e.what());
435fa5e4d32SSunny Srivastava         throw e;
436fa5e4d32SSunny Srivastava     }
437fa5e4d32SSunny Srivastava }
438fa5e4d32SSunny Srivastava 
getKeywordValueFromRecord(const types::Record & i_recordName,const types::Keyword & i_keywordName,const types::RecordOffset & i_recordDataOffset)439fa5e4d32SSunny Srivastava types::BinaryVector IpzVpdParser::getKeywordValueFromRecord(
440fa5e4d32SSunny Srivastava     const types::Record& i_recordName, const types::Keyword& i_keywordName,
441fa5e4d32SSunny Srivastava     const types::RecordOffset& i_recordDataOffset)
442fa5e4d32SSunny Srivastava {
443fa5e4d32SSunny Srivastava     auto l_iterator = m_vpdVector.cbegin();
444fa5e4d32SSunny Srivastava 
445fa5e4d32SSunny Srivastava     // Go to the record name in the given record's offset
446fa5e4d32SSunny Srivastava     std::ranges::advance(l_iterator,
447fa5e4d32SSunny Srivastava                          i_recordDataOffset + Length::JUMP_TO_RECORD_NAME,
448fa5e4d32SSunny Srivastava                          m_vpdVector.cend());
449fa5e4d32SSunny Srivastava 
450fa5e4d32SSunny Srivastava     // Check if the record is present in the given record's offset
451fa5e4d32SSunny Srivastava     if (i_recordName !=
452fa5e4d32SSunny Srivastava         std::string(l_iterator,
453fa5e4d32SSunny Srivastava                     std::ranges::next(l_iterator, Length::RECORD_NAME,
454fa5e4d32SSunny Srivastava                                       m_vpdVector.cend())))
455fa5e4d32SSunny Srivastava     {
456fa5e4d32SSunny Srivastava         throw std::runtime_error(
457fa5e4d32SSunny Srivastava             "Given record is not present in the offset provided");
458fa5e4d32SSunny Srivastava     }
459fa5e4d32SSunny Srivastava 
460fa5e4d32SSunny Srivastava     std::ranges::advance(l_iterator, Length::RECORD_NAME, m_vpdVector.cend());
461fa5e4d32SSunny Srivastava 
462fa5e4d32SSunny Srivastava     std::string l_kwName = std::string(
463fa5e4d32SSunny Srivastava         l_iterator,
464fa5e4d32SSunny Srivastava         std::ranges::next(l_iterator, Length::KW_NAME, m_vpdVector.cend()));
465fa5e4d32SSunny Srivastava 
466fa5e4d32SSunny Srivastava     // Iterate through the keywords until the last keyword PF is found.
467fa5e4d32SSunny Srivastava     while (l_kwName != constants::LAST_KW)
468fa5e4d32SSunny Srivastava     {
469fa5e4d32SSunny Srivastava         // First character required for #D keyword check
470fa5e4d32SSunny Srivastava         char l_kwNameStart = *l_iterator;
471fa5e4d32SSunny Srivastava 
472fa5e4d32SSunny Srivastava         std::ranges::advance(l_iterator, Length::KW_NAME, m_vpdVector.cend());
473fa5e4d32SSunny Srivastava 
474fa5e4d32SSunny Srivastava         // Get the keyword's data length
475fa5e4d32SSunny Srivastava         auto l_kwdDataLength = 0;
476fa5e4d32SSunny Srivastava 
477fa5e4d32SSunny Srivastava         if (constants::POUND_KW == l_kwNameStart)
478fa5e4d32SSunny Srivastava         {
479fa5e4d32SSunny Srivastava             l_kwdDataLength = readUInt16LE(l_iterator);
480fa5e4d32SSunny Srivastava             std::ranges::advance(l_iterator, sizeof(types::PoundKwSize),
481fa5e4d32SSunny Srivastava                                  m_vpdVector.cend());
482fa5e4d32SSunny Srivastava         }
483fa5e4d32SSunny Srivastava         else
484fa5e4d32SSunny Srivastava         {
485fa5e4d32SSunny Srivastava             l_kwdDataLength = *l_iterator;
486fa5e4d32SSunny Srivastava             std::ranges::advance(l_iterator, sizeof(types::KwSize),
487fa5e4d32SSunny Srivastava                                  m_vpdVector.cend());
488fa5e4d32SSunny Srivastava         }
489fa5e4d32SSunny Srivastava 
490fa5e4d32SSunny Srivastava         if (l_kwName == i_keywordName)
491fa5e4d32SSunny Srivastava         {
492fa5e4d32SSunny Srivastava             // Return keyword's value to the caller
493fa5e4d32SSunny Srivastava             return types::BinaryVector(
494fa5e4d32SSunny Srivastava                 l_iterator, std::ranges::next(l_iterator, l_kwdDataLength,
495fa5e4d32SSunny Srivastava                                               m_vpdVector.cend()));
496fa5e4d32SSunny Srivastava         }
497fa5e4d32SSunny Srivastava 
498fa5e4d32SSunny Srivastava         // next keyword search
499fa5e4d32SSunny Srivastava         std::ranges::advance(l_iterator, l_kwdDataLength, m_vpdVector.cend());
500fa5e4d32SSunny Srivastava 
501fa5e4d32SSunny Srivastava         // next keyword name
502fa5e4d32SSunny Srivastava         l_kwName = std::string(
503fa5e4d32SSunny Srivastava             l_iterator,
504fa5e4d32SSunny Srivastava             std::ranges::next(l_iterator, Length::KW_NAME, m_vpdVector.cend()));
505fa5e4d32SSunny Srivastava     }
506fa5e4d32SSunny Srivastava 
507fa5e4d32SSunny Srivastava     // Keyword not found
508fa5e4d32SSunny Srivastava     throw std::runtime_error("Given keyword not found.");
509fa5e4d32SSunny Srivastava }
510fa5e4d32SSunny Srivastava 
getRecordDetailsFromVTOC(const types::Record & i_recordName,const types::RecordOffset & i_vtocOffset)511fa5e4d32SSunny Srivastava types::RecordData IpzVpdParser::getRecordDetailsFromVTOC(
512fa5e4d32SSunny Srivastava     const types::Record& i_recordName, const types::RecordOffset& i_vtocOffset)
513fa5e4d32SSunny Srivastava {
514fa5e4d32SSunny Srivastava     // Get VTOC's PT keyword value.
515fa5e4d32SSunny Srivastava     const auto l_vtocPTKwValue =
516fa5e4d32SSunny Srivastava         getKeywordValueFromRecord("VTOC", "PT", i_vtocOffset);
517fa5e4d32SSunny Srivastava 
518fa5e4d32SSunny Srivastava     // Parse through VTOC PT keyword value to find the record which we are
519fa5e4d32SSunny Srivastava     // interested in.
520fa5e4d32SSunny Srivastava     auto l_vtocPTItr = l_vtocPTKwValue.cbegin();
521fa5e4d32SSunny Srivastava 
522fa5e4d32SSunny Srivastava     types::RecordData l_recordData;
523fa5e4d32SSunny Srivastava 
524fa5e4d32SSunny Srivastava     while (l_vtocPTItr < l_vtocPTKwValue.cend())
525fa5e4d32SSunny Srivastava     {
526fa5e4d32SSunny Srivastava         if (i_recordName ==
527fa5e4d32SSunny Srivastava             std::string(l_vtocPTItr, l_vtocPTItr + Length::RECORD_NAME))
528fa5e4d32SSunny Srivastava         {
529fa5e4d32SSunny Srivastava             // Record found in VTOC PT keyword. Get offset
530fa5e4d32SSunny Srivastava             std::ranges::advance(l_vtocPTItr,
531fa5e4d32SSunny Srivastava                                  Length::RECORD_NAME + Length::RECORD_TYPE,
532fa5e4d32SSunny Srivastava                                  l_vtocPTKwValue.cend());
533fa5e4d32SSunny Srivastava             const auto l_recordOffset = readUInt16LE(l_vtocPTItr);
534fa5e4d32SSunny Srivastava 
535fa5e4d32SSunny Srivastava             std::ranges::advance(l_vtocPTItr, Length::RECORD_OFFSET,
536fa5e4d32SSunny Srivastava                                  l_vtocPTKwValue.cend());
537fa5e4d32SSunny Srivastava             const auto l_recordLength = readUInt16LE(l_vtocPTItr);
538fa5e4d32SSunny Srivastava 
539fa5e4d32SSunny Srivastava             std::ranges::advance(l_vtocPTItr, Length::RECORD_LENGTH,
540fa5e4d32SSunny Srivastava                                  l_vtocPTKwValue.cend());
541fa5e4d32SSunny Srivastava             const auto l_eccOffset = readUInt16LE(l_vtocPTItr);
542fa5e4d32SSunny Srivastava 
543fa5e4d32SSunny Srivastava             std::ranges::advance(l_vtocPTItr, Length::RECORD_ECC_OFFSET,
544fa5e4d32SSunny Srivastava                                  l_vtocPTKwValue.cend());
545fa5e4d32SSunny Srivastava             const auto l_eccLength = readUInt16LE(l_vtocPTItr);
546fa5e4d32SSunny Srivastava 
547fa5e4d32SSunny Srivastava             l_recordData = std::make_tuple(l_recordOffset, l_recordLength,
548fa5e4d32SSunny Srivastava                                            l_eccOffset, l_eccLength);
549fa5e4d32SSunny Srivastava             break;
550fa5e4d32SSunny Srivastava         }
551fa5e4d32SSunny Srivastava 
552fa5e4d32SSunny Srivastava         std::ranges::advance(l_vtocPTItr, Length::SKIP_A_RECORD_IN_PT,
553fa5e4d32SSunny Srivastava                              l_vtocPTKwValue.cend());
554fa5e4d32SSunny Srivastava     }
555fa5e4d32SSunny Srivastava 
556fa5e4d32SSunny Srivastava     return l_recordData;
557fa5e4d32SSunny Srivastava }
558fa5e4d32SSunny Srivastava 
readKeywordFromHardware(const types::ReadVpdParams i_paramsToReadData)559fa5e4d32SSunny Srivastava types::DbusVariantType IpzVpdParser::readKeywordFromHardware(
560fa5e4d32SSunny Srivastava     const types::ReadVpdParams i_paramsToReadData)
561fa5e4d32SSunny Srivastava {
562fa5e4d32SSunny Srivastava     // Extract record and keyword from i_paramsToReadData
563fa5e4d32SSunny Srivastava     types::Record l_record;
564fa5e4d32SSunny Srivastava     types::Keyword l_keyword;
565fa5e4d32SSunny Srivastava 
566fa5e4d32SSunny Srivastava     if (const types::IpzType* l_ipzData =
567fa5e4d32SSunny Srivastava             std::get_if<types::IpzType>(&i_paramsToReadData))
568fa5e4d32SSunny Srivastava     {
569fa5e4d32SSunny Srivastava         l_record = std::get<0>(*l_ipzData);
570fa5e4d32SSunny Srivastava         l_keyword = std::get<1>(*l_ipzData);
571fa5e4d32SSunny Srivastava     }
572fa5e4d32SSunny Srivastava     else
573fa5e4d32SSunny Srivastava     {
574fa5e4d32SSunny Srivastava         logging::logMessage(
575fa5e4d32SSunny Srivastava             "Input parameter type provided isn't compatible with the given VPD type.");
576fa5e4d32SSunny Srivastava         throw types::DbusInvalidArgument();
577fa5e4d32SSunny Srivastava     }
578fa5e4d32SSunny Srivastava 
579fa5e4d32SSunny Srivastava     // Read keyword's value from vector
580fa5e4d32SSunny Srivastava     auto l_itrToVPD = m_vpdVector.cbegin();
581fa5e4d32SSunny Srivastava 
582fa5e4d32SSunny Srivastava     if (l_record == "VHDR")
583fa5e4d32SSunny Srivastava     {
584fa5e4d32SSunny Srivastava // Disable providing a way to read keywords from VHDR for the time being.
585fa5e4d32SSunny Srivastava #if 0
586fa5e4d32SSunny Srivastava         std::ranges::advance(l_itrToVPD, Offset::VHDR_RECORD,
587fa5e4d32SSunny Srivastava                              m_vpdVector.cend());
588fa5e4d32SSunny Srivastava 
589fa5e4d32SSunny Srivastava         return types::DbusVariantType{getKeywordValueFromRecord(
590fa5e4d32SSunny Srivastava             l_record, l_keyword, Offset::VHDR_RECORD)};
591fa5e4d32SSunny Srivastava #endif
592fa5e4d32SSunny Srivastava 
593fa5e4d32SSunny Srivastava         logging::logMessage("Read cannot be performed on VHDR record.");
594fa5e4d32SSunny Srivastava         throw types::DbusInvalidArgument();
595fa5e4d32SSunny Srivastava     }
596fa5e4d32SSunny Srivastava 
597fa5e4d32SSunny Srivastava     // Get VTOC offset
598fa5e4d32SSunny Srivastava     std::ranges::advance(l_itrToVPD, Offset::VTOC_PTR, m_vpdVector.cend());
599fa5e4d32SSunny Srivastava     auto l_vtocOffset = readUInt16LE(l_itrToVPD);
600fa5e4d32SSunny Srivastava 
601fa5e4d32SSunny Srivastava     if (l_record == "VTOC")
602fa5e4d32SSunny Srivastava     {
603fa5e4d32SSunny Srivastava         // Disable providing a way to read keywords from VTOC for the time
604fa5e4d32SSunny Srivastava         // being.
605fa5e4d32SSunny Srivastava #if 0
606fa5e4d32SSunny Srivastava         return types::DbusVariantType{
607fa5e4d32SSunny Srivastava             getKeywordValueFromRecord(l_record, l_keyword, l_vtocOffset)};
608fa5e4d32SSunny Srivastava #endif
609fa5e4d32SSunny Srivastava 
610fa5e4d32SSunny Srivastava         logging::logMessage("Read cannot be performed on VTOC record.");
611fa5e4d32SSunny Srivastava         throw types::DbusInvalidArgument();
612fa5e4d32SSunny Srivastava     }
613fa5e4d32SSunny Srivastava 
614fa5e4d32SSunny Srivastava     // Get record offset from VTOC's PT keyword value.
615fa5e4d32SSunny Srivastava     auto l_recordData = getRecordDetailsFromVTOC(l_record, l_vtocOffset);
616fa5e4d32SSunny Srivastava     const auto l_recordOffset = std::get<0>(l_recordData);
617fa5e4d32SSunny Srivastava 
618fa5e4d32SSunny Srivastava     if (l_recordOffset == 0)
619fa5e4d32SSunny Srivastava     {
620fa5e4d32SSunny Srivastava         throw std::runtime_error("Record not found in VTOC PT keyword.");
621fa5e4d32SSunny Srivastava     }
622fa5e4d32SSunny Srivastava 
623fa5e4d32SSunny Srivastava     // Get the given keyword's value
624fa5e4d32SSunny Srivastava     return types::DbusVariantType{
625fa5e4d32SSunny Srivastava         getKeywordValueFromRecord(l_record, l_keyword, l_recordOffset)};
626fa5e4d32SSunny Srivastava }
627fa5e4d32SSunny Srivastava 
updateRecordECC(const auto & i_recordDataOffset,const auto & i_recordDataLength,const auto & i_recordECCOffset,size_t i_recordECCLength,types::BinaryVector & io_vpdVector)628fa5e4d32SSunny Srivastava void IpzVpdParser::updateRecordECC(
629fa5e4d32SSunny Srivastava     const auto& i_recordDataOffset, const auto& i_recordDataLength,
630fa5e4d32SSunny Srivastava     const auto& i_recordECCOffset, size_t i_recordECCLength,
631fa5e4d32SSunny Srivastava     types::BinaryVector& io_vpdVector)
632fa5e4d32SSunny Srivastava {
633fa5e4d32SSunny Srivastava     auto l_recordDataBegin =
634fa5e4d32SSunny Srivastava         std::next(io_vpdVector.begin(), i_recordDataOffset);
635fa5e4d32SSunny Srivastava 
636fa5e4d32SSunny Srivastava     auto l_recordECCBegin = std::next(io_vpdVector.begin(), i_recordECCOffset);
637fa5e4d32SSunny Srivastava 
638fa5e4d32SSunny Srivastava     auto l_eccStatus = vpdecc_create_ecc(
639fa5e4d32SSunny Srivastava         const_cast<uint8_t*>(&l_recordDataBegin[0]), i_recordDataLength,
640fa5e4d32SSunny Srivastava         const_cast<uint8_t*>(&l_recordECCBegin[0]), &i_recordECCLength);
641fa5e4d32SSunny Srivastava 
642fa5e4d32SSunny Srivastava     if (l_eccStatus != VPD_ECC_OK)
643fa5e4d32SSunny Srivastava     {
644fa5e4d32SSunny Srivastava         throw(EccException("ECC update failed with error " + l_eccStatus));
645fa5e4d32SSunny Srivastava     }
646fa5e4d32SSunny Srivastava 
647fa5e4d32SSunny Srivastava     auto l_recordECCEnd = std::next(l_recordECCBegin, i_recordECCLength);
648fa5e4d32SSunny Srivastava 
649fa5e4d32SSunny Srivastava     m_vpdFileStream.seekp(m_vpdStartOffset + i_recordECCOffset, std::ios::beg);
650fa5e4d32SSunny Srivastava 
651fa5e4d32SSunny Srivastava     std::copy(l_recordECCBegin, l_recordECCEnd,
652fa5e4d32SSunny Srivastava               std::ostreambuf_iterator<char>(m_vpdFileStream));
653fa5e4d32SSunny Srivastava }
654fa5e4d32SSunny Srivastava 
setKeywordValueInRecord(const types::Record & i_recordName,const types::Keyword & i_keywordName,const types::BinaryVector & i_keywordData,const types::RecordOffset & i_recordDataOffset,types::BinaryVector & io_vpdVector)655fa5e4d32SSunny Srivastava int IpzVpdParser::setKeywordValueInRecord(
656fa5e4d32SSunny Srivastava     const types::Record& i_recordName, const types::Keyword& i_keywordName,
657fa5e4d32SSunny Srivastava     const types::BinaryVector& i_keywordData,
658fa5e4d32SSunny Srivastava     const types::RecordOffset& i_recordDataOffset,
659fa5e4d32SSunny Srivastava     types::BinaryVector& io_vpdVector)
660fa5e4d32SSunny Srivastava {
661fa5e4d32SSunny Srivastava     auto l_iterator = io_vpdVector.begin();
662fa5e4d32SSunny Srivastava 
663fa5e4d32SSunny Srivastava     // Go to the record name in the given record's offset
664fa5e4d32SSunny Srivastava     std::ranges::advance(l_iterator,
665fa5e4d32SSunny Srivastava                          i_recordDataOffset + Length::JUMP_TO_RECORD_NAME,
666fa5e4d32SSunny Srivastava                          io_vpdVector.end());
667fa5e4d32SSunny Srivastava 
668fa5e4d32SSunny Srivastava     const std::string l_recordFound(
669fa5e4d32SSunny Srivastava         l_iterator,
670fa5e4d32SSunny Srivastava         std::ranges::next(l_iterator, Length::RECORD_NAME, io_vpdVector.end()));
671fa5e4d32SSunny Srivastava 
672fa5e4d32SSunny Srivastava     // Check if the record is present in the given record's offset
673fa5e4d32SSunny Srivastava     if (i_recordName != l_recordFound)
674fa5e4d32SSunny Srivastava     {
675fa5e4d32SSunny Srivastava         throw(DataException("Given record found at the offset " +
676fa5e4d32SSunny Srivastava                             std::to_string(i_recordDataOffset) + " is : " +
677fa5e4d32SSunny Srivastava                             l_recordFound + " and not " + i_recordName));
678fa5e4d32SSunny Srivastava     }
679fa5e4d32SSunny Srivastava 
680fa5e4d32SSunny Srivastava     std::ranges::advance(l_iterator, Length::RECORD_NAME, io_vpdVector.end());
681fa5e4d32SSunny Srivastava 
682fa5e4d32SSunny Srivastava     std::string l_kwName = std::string(
683fa5e4d32SSunny Srivastava         l_iterator,
684fa5e4d32SSunny Srivastava         std::ranges::next(l_iterator, Length::KW_NAME, io_vpdVector.end()));
685fa5e4d32SSunny Srivastava 
686fa5e4d32SSunny Srivastava     // Iterate through the keywords until the last keyword PF is found.
687fa5e4d32SSunny Srivastava     while (l_kwName != constants::LAST_KW)
688fa5e4d32SSunny Srivastava     {
689fa5e4d32SSunny Srivastava         // First character required for #D keyword check
690fa5e4d32SSunny Srivastava         char l_kwNameStart = *l_iterator;
691fa5e4d32SSunny Srivastava 
692fa5e4d32SSunny Srivastava         std::ranges::advance(l_iterator, Length::KW_NAME, io_vpdVector.end());
693fa5e4d32SSunny Srivastava 
694fa5e4d32SSunny Srivastava         // Find the keyword's data length
695fa5e4d32SSunny Srivastava         size_t l_kwdDataLength = 0;
696fa5e4d32SSunny Srivastava 
697fa5e4d32SSunny Srivastava         if (constants::POUND_KW == l_kwNameStart)
698fa5e4d32SSunny Srivastava         {
699fa5e4d32SSunny Srivastava             l_kwdDataLength = readUInt16LE(l_iterator);
700fa5e4d32SSunny Srivastava             std::ranges::advance(l_iterator, sizeof(types::PoundKwSize),
701fa5e4d32SSunny Srivastava                                  io_vpdVector.end());
702fa5e4d32SSunny Srivastava         }
703fa5e4d32SSunny Srivastava         else
704fa5e4d32SSunny Srivastava         {
705fa5e4d32SSunny Srivastava             l_kwdDataLength = *l_iterator;
706fa5e4d32SSunny Srivastava             std::ranges::advance(l_iterator, sizeof(types::KwSize),
707fa5e4d32SSunny Srivastava                                  io_vpdVector.end());
708fa5e4d32SSunny Srivastava         }
709fa5e4d32SSunny Srivastava 
710fa5e4d32SSunny Srivastava         if (l_kwName == i_keywordName)
711fa5e4d32SSunny Srivastava         {
712fa5e4d32SSunny Srivastava             // Before writing the keyword's value, get the maximum size that can
713fa5e4d32SSunny Srivastava             // be updated.
714fa5e4d32SSunny Srivastava             const auto l_lengthToUpdate =
715fa5e4d32SSunny Srivastava                 i_keywordData.size() <= l_kwdDataLength
716fa5e4d32SSunny Srivastava                     ? i_keywordData.size()
717fa5e4d32SSunny Srivastava                     : l_kwdDataLength;
718fa5e4d32SSunny Srivastava 
719fa5e4d32SSunny Srivastava             // Set the keyword's value on vector. This is required to update the
720fa5e4d32SSunny Srivastava             // record's ECC based on the new value set.
721fa5e4d32SSunny Srivastava             const auto i_keywordDataEnd = std::ranges::next(
722fa5e4d32SSunny Srivastava                 i_keywordData.cbegin(), l_lengthToUpdate, i_keywordData.cend());
723fa5e4d32SSunny Srivastava 
724fa5e4d32SSunny Srivastava             std::copy(i_keywordData.cbegin(), i_keywordDataEnd, l_iterator);
725fa5e4d32SSunny Srivastava 
726fa5e4d32SSunny Srivastava             // Set the keyword's value on hardware
727fa5e4d32SSunny Srivastava             const auto l_kwdDataOffset =
728fa5e4d32SSunny Srivastava                 std::distance(io_vpdVector.begin(), l_iterator);
729fa5e4d32SSunny Srivastava             m_vpdFileStream.seekp(m_vpdStartOffset + l_kwdDataOffset,
730fa5e4d32SSunny Srivastava                                   std::ios::beg);
731fa5e4d32SSunny Srivastava 
732fa5e4d32SSunny Srivastava             std::copy(i_keywordData.cbegin(), i_keywordDataEnd,
733fa5e4d32SSunny Srivastava                       std::ostreambuf_iterator<char>(m_vpdFileStream));
734fa5e4d32SSunny Srivastava 
735fa5e4d32SSunny Srivastava             // return no of bytes set
736fa5e4d32SSunny Srivastava             return l_lengthToUpdate;
737fa5e4d32SSunny Srivastava         }
738fa5e4d32SSunny Srivastava 
739fa5e4d32SSunny Srivastava         // next keyword search
740fa5e4d32SSunny Srivastava         std::ranges::advance(l_iterator, l_kwdDataLength, io_vpdVector.end());
741fa5e4d32SSunny Srivastava 
742fa5e4d32SSunny Srivastava         // next keyword name
743fa5e4d32SSunny Srivastava         l_kwName = std::string(
744fa5e4d32SSunny Srivastava             l_iterator,
745fa5e4d32SSunny Srivastava             std::ranges::next(l_iterator, Length::KW_NAME, io_vpdVector.end()));
746fa5e4d32SSunny Srivastava     }
747fa5e4d32SSunny Srivastava 
748fa5e4d32SSunny Srivastava     // Keyword not found
749fa5e4d32SSunny Srivastava     throw(DataException(
750fa5e4d32SSunny Srivastava         "Keyword " + i_keywordName + " not found in record " + i_recordName));
751fa5e4d32SSunny Srivastava }
752fa5e4d32SSunny Srivastava 
writeKeywordOnHardware(const types::WriteVpdParams i_paramsToWriteData)753fa5e4d32SSunny Srivastava int IpzVpdParser::writeKeywordOnHardware(
754fa5e4d32SSunny Srivastava     const types::WriteVpdParams i_paramsToWriteData)
755fa5e4d32SSunny Srivastava {
756fa5e4d32SSunny Srivastava     int l_sizeWritten = -1;
757fa5e4d32SSunny Srivastava 
758fa5e4d32SSunny Srivastava     try
759fa5e4d32SSunny Srivastava     {
760fa5e4d32SSunny Srivastava         types::Record l_recordName;
761fa5e4d32SSunny Srivastava         types::Keyword l_keywordName;
762fa5e4d32SSunny Srivastava         types::BinaryVector l_keywordData;
763fa5e4d32SSunny Srivastava 
764fa5e4d32SSunny Srivastava         // Extract record, keyword and value from i_paramsToWriteData
765fa5e4d32SSunny Srivastava         if (const types::IpzData* l_ipzData =
766fa5e4d32SSunny Srivastava                 std::get_if<types::IpzData>(&i_paramsToWriteData))
767fa5e4d32SSunny Srivastava         {
768fa5e4d32SSunny Srivastava             l_recordName = std::get<0>(*l_ipzData);
769fa5e4d32SSunny Srivastava             l_keywordName = std::get<1>(*l_ipzData);
770fa5e4d32SSunny Srivastava             l_keywordData = std::get<2>(*l_ipzData);
771fa5e4d32SSunny Srivastava         }
772fa5e4d32SSunny Srivastava         else
773fa5e4d32SSunny Srivastava         {
774fa5e4d32SSunny Srivastava             logging::logMessage(
775fa5e4d32SSunny Srivastava                 "Input parameter type provided isn't compatible with the given FRU's VPD type.");
776fa5e4d32SSunny Srivastava             throw types::DbusInvalidArgument();
777fa5e4d32SSunny Srivastava         }
778fa5e4d32SSunny Srivastava 
779fa5e4d32SSunny Srivastava         if (l_recordName == "VHDR" || l_recordName == "VTOC")
780fa5e4d32SSunny Srivastava         {
781fa5e4d32SSunny Srivastava             logging::logMessage(
782fa5e4d32SSunny Srivastava                 "Write operation not allowed on the given record : " +
783fa5e4d32SSunny Srivastava                 l_recordName);
784fa5e4d32SSunny Srivastava             throw types::DbusNotAllowed();
785fa5e4d32SSunny Srivastava         }
786fa5e4d32SSunny Srivastava 
787fa5e4d32SSunny Srivastava         if (l_keywordData.size() == 0)
788fa5e4d32SSunny Srivastava         {
789fa5e4d32SSunny Srivastava             logging::logMessage(
790fa5e4d32SSunny Srivastava                 "Write operation not allowed as the given keyword's data length is 0.");
791fa5e4d32SSunny Srivastava             throw types::DbusInvalidArgument();
792fa5e4d32SSunny Srivastava         }
793fa5e4d32SSunny Srivastava 
794fa5e4d32SSunny Srivastava         auto l_vpdBegin = m_vpdVector.begin();
795fa5e4d32SSunny Srivastava 
796fa5e4d32SSunny Srivastava         // Get VTOC offset
797fa5e4d32SSunny Srivastava         std::ranges::advance(l_vpdBegin, Offset::VTOC_PTR, m_vpdVector.end());
798fa5e4d32SSunny Srivastava         auto l_vtocOffset = readUInt16LE(l_vpdBegin);
799fa5e4d32SSunny Srivastava 
800fa5e4d32SSunny Srivastava         // Get the details of user given record from VTOC
801fa5e4d32SSunny Srivastava         const types::RecordData& l_inputRecordDetails =
802fa5e4d32SSunny Srivastava             getRecordDetailsFromVTOC(l_recordName, l_vtocOffset);
803fa5e4d32SSunny Srivastava 
804fa5e4d32SSunny Srivastava         const auto& l_inputRecordOffset = std::get<0>(l_inputRecordDetails);
805fa5e4d32SSunny Srivastava 
806fa5e4d32SSunny Srivastava         if (l_inputRecordOffset == 0)
807fa5e4d32SSunny Srivastava         {
808fa5e4d32SSunny Srivastava             throw(DataException("Record not found in VTOC PT keyword."));
809fa5e4d32SSunny Srivastava         }
810fa5e4d32SSunny Srivastava 
811fa5e4d32SSunny Srivastava         // Create a local copy of m_vpdVector to perform keyword update and ecc
812fa5e4d32SSunny Srivastava         // update on filestream.
813fa5e4d32SSunny Srivastava         types::BinaryVector l_vpdVector = m_vpdVector;
814fa5e4d32SSunny Srivastava 
815fa5e4d32SSunny Srivastava         // write keyword's value on hardware
816fa5e4d32SSunny Srivastava         l_sizeWritten =
817fa5e4d32SSunny Srivastava             setKeywordValueInRecord(l_recordName, l_keywordName, l_keywordData,
818fa5e4d32SSunny Srivastava                                     l_inputRecordOffset, l_vpdVector);
819fa5e4d32SSunny Srivastava 
820fa5e4d32SSunny Srivastava         if (l_sizeWritten <= 0)
821fa5e4d32SSunny Srivastava         {
822fa5e4d32SSunny Srivastava             throw(DataException("Unable to set value on " + l_recordName + ":" +
823fa5e4d32SSunny Srivastava                                 l_keywordName));
824fa5e4d32SSunny Srivastava         }
825fa5e4d32SSunny Srivastava 
826fa5e4d32SSunny Srivastava         // Update the record's ECC
827fa5e4d32SSunny Srivastava         updateRecordECC(l_inputRecordOffset, std::get<1>(l_inputRecordDetails),
828fa5e4d32SSunny Srivastava                         std::get<2>(l_inputRecordDetails),
829fa5e4d32SSunny Srivastava                         std::get<3>(l_inputRecordDetails), l_vpdVector);
830fa5e4d32SSunny Srivastava 
831fa5e4d32SSunny Srivastava         logging::logMessage(std::to_string(l_sizeWritten) +
832fa5e4d32SSunny Srivastava                             " bytes updated successfully on hardware for " +
833fa5e4d32SSunny Srivastava                             l_recordName + ":" + l_keywordName);
834fa5e4d32SSunny Srivastava     }
835fa5e4d32SSunny Srivastava     catch (const std::exception& l_exception)
836fa5e4d32SSunny Srivastava     {
837fa5e4d32SSunny Srivastava         throw;
838fa5e4d32SSunny Srivastava     }
839fa5e4d32SSunny Srivastava 
840fa5e4d32SSunny Srivastava     return l_sizeWritten;
841fa5e4d32SSunny Srivastava }
842fa5e4d32SSunny Srivastava } // namespace vpd
843