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