blob: 70eb453ed0db1c21dbb66166924af5ce6f2be2e8 [file] [log] [blame]
SunnySrivastava1984a7392592020-03-09 10:19:33 -05001#include "config.h"
2
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -06003#include "editor_impl.hpp"
4
SunnySrivastava19846d8314d2020-05-15 09:34:58 -05005#include "parser.hpp"
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -06006#include "utils.hpp"
7
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -06008#include "vpdecc/vpdecc.h"
9
10namespace openpower
11{
12namespace vpd
13{
14namespace manager
15{
16namespace editor
17{
18using namespace openpower::vpd::constants;
19
20void EditorImpl::checkPTForRecord(Binary::const_iterator& iterator,
21 Byte ptLength)
22{
23 // auto iterator = ptRecord.cbegin();
24 auto end = std::next(iterator, ptLength + 1);
25
26 // Look at each entry in the PT keyword for the record name
27 while (iterator < end)
28 {
29 auto stop = std::next(iterator, lengths::RECORD_NAME);
30 std::string record(iterator, stop);
31
32 if (record == thisRecord.recName)
33 {
34 // Skip record name and record type
35 std::advance(iterator, lengths::RECORD_NAME + sizeof(RecordType));
36
37 // Get record offset
38 thisRecord.recOffset = readUInt16LE(iterator);
39
40 // pass the record offset length to read record length
41 std::advance(iterator, lengths::RECORD_OFFSET);
42 thisRecord.recSize = readUInt16LE(iterator);
43
44 std::advance(iterator, lengths::RECORD_LENGTH);
45 thisRecord.recECCoffset = readUInt16LE(iterator);
46
47 ECCLength len;
48 std::advance(iterator, lengths::RECORD_ECC_OFFSET);
49 len = readUInt16LE(iterator);
50 thisRecord.recECCLength = len;
51
52 // once we find the record we don't need to look further
53 return;
54 }
55 else
56 {
57 // Jump the record
58 std::advance(iterator, lengths::RECORD_NAME + sizeof(RecordType) +
59 sizeof(RecordOffset) +
60 sizeof(RecordLength) +
61 sizeof(ECCOffset) + sizeof(ECCLength));
62 }
63 }
64
65 // imples the record was not found
66 throw std::runtime_error("Record not found");
67}
68
SunnySrivastava19846d8314d2020-05-15 09:34:58 -050069void EditorImpl::updateData(const Binary& kwdData)
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -060070{
71 std::size_t lengthToUpdate = kwdData.size() <= thisRecord.kwdDataLength
72 ? kwdData.size()
73 : thisRecord.kwdDataLength;
74
75 auto iteratorToNewdata = kwdData.cbegin();
76 auto end = iteratorToNewdata;
77 std::advance(end, lengthToUpdate);
78
SunnySrivastava19846d8314d2020-05-15 09:34:58 -050079 // update data in file buffer as it will be needed to update ECC
80 // avoiding extra stream operation here
81 auto iteratorToKWdData = vpdFile.begin();
82 std::advance(iteratorToKWdData, thisRecord.kwDataOffset);
83 std::copy(iteratorToNewdata, end, iteratorToKWdData);
84
85 // update data in EEPROM as well. As we will not write complete file back
86 vpdFileStream.seekg(thisRecord.kwDataOffset, std::ios::beg);
87 iteratorToNewdata = kwdData.cbegin();
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -060088 std::copy(iteratorToNewdata, end,
89 std::ostreambuf_iterator<char>(vpdFileStream));
SunnySrivastava19846d8314d2020-05-15 09:34:58 -050090
91 // get a hold to new data in case encoding is needed
92 thisRecord.kwdUpdatedData.resize(thisRecord.kwdDataLength);
93 auto itrToKWdData = vpdFile.cbegin();
94 std::advance(itrToKWdData, thisRecord.kwDataOffset);
95 auto kwdDataEnd = itrToKWdData;
96 std::advance(kwdDataEnd, thisRecord.kwdDataLength);
97 std::copy(itrToKWdData, kwdDataEnd, thisRecord.kwdUpdatedData.begin());
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -060098}
99
100void EditorImpl::checkRecordForKwd()
101{
102 RecordOffset recOffset = thisRecord.recOffset;
103
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500104 // Amount to skip for record ID, size, and the RT keyword
105 constexpr auto skipBeg = sizeof(RecordId) + sizeof(RecordSize) +
106 lengths::KW_NAME + sizeof(KwSize);
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600107
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500108 auto iterator = vpdFile.cbegin();
109 std::advance(iterator, recOffset + skipBeg + lengths::RECORD_NAME);
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600110
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500111 auto end = iterator;
112 std::advance(end, thisRecord.recSize);
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600113 std::size_t dataLength = 0;
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500114
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600115 while (iterator < end)
116 {
117 // Note keyword name
118 std::string kw(iterator, iterator + lengths::KW_NAME);
119
120 // Check if the Keyword starts with '#'
121 char kwNameStart = *iterator;
122 std::advance(iterator, lengths::KW_NAME);
123
124 // if keyword starts with #
125 if (POUND_KW == kwNameStart)
126 {
127 // Note existing keyword data length
128 dataLength = readUInt16LE(iterator);
129
130 // Jump past 2Byte keyword length + data
131 std::advance(iterator, sizeof(PoundKwSize));
132 }
133 else
134 {
135 // Note existing keyword data length
136 dataLength = *iterator;
137
138 // Jump past keyword length and data
139 std::advance(iterator, sizeof(KwSize));
140 }
141
142 if (thisRecord.recKWd == kw)
143 {
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500144 thisRecord.kwDataOffset = std::distance(vpdFile.cbegin(), iterator);
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600145 thisRecord.kwdDataLength = dataLength;
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600146 return;
147 }
148
149 // jump the data of current kwd to point to next kwd name
150 std::advance(iterator, dataLength);
151 }
152
153 throw std::runtime_error("Keyword not found");
154}
155
156void EditorImpl::updateRecordECC()
157{
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500158 auto itrToRecordData = vpdFile.cbegin();
159 std::advance(itrToRecordData, thisRecord.recOffset);
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600160
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500161 auto itrToRecordECC = vpdFile.cbegin();
162 std::advance(itrToRecordECC, thisRecord.recECCoffset);
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600163
164 auto l_status = vpdecc_create_ecc(
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500165 const_cast<uint8_t*>(&itrToRecordData[0]), thisRecord.recSize,
166 const_cast<uint8_t*>(&itrToRecordECC[0]), &thisRecord.recECCLength);
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600167 if (l_status != VPD_ECC_OK)
168 {
169 throw std::runtime_error("Ecc update failed");
170 }
171
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500172 auto end = itrToRecordECC;
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600173 std::advance(end, thisRecord.recECCLength);
174
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500175 vpdFileStream.seekp(thisRecord.recECCoffset, std::ios::beg);
176 std::copy(itrToRecordECC, end,
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600177 std::ostreambuf_iterator<char>(vpdFileStream));
178}
179
180auto EditorImpl::getValue(offsets::Offsets offset)
181{
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500182 auto itr = vpdFile.cbegin();
183 std::advance(itr, offset);
184 LE2ByteData lowByte = *itr;
185 LE2ByteData highByte = *(itr + 1);
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600186 lowByte |= (highByte << 8);
187
188 return lowByte;
189}
190
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500191void EditorImpl::checkECC(Binary::const_iterator& itrToRecData,
192 Binary::const_iterator& itrToECCData,
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600193 RecordLength recLength, ECCLength eccLength)
194{
195 auto l_status =
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500196 vpdecc_check_data(const_cast<uint8_t*>(&itrToRecData[0]), recLength,
197 const_cast<uint8_t*>(&itrToECCData[0]), eccLength);
198
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600199 if (l_status != VPD_ECC_OK)
200 {
201 throw std::runtime_error("Ecc check failed for VTOC");
202 }
203}
204
205void EditorImpl::readVTOC()
206{
207 // read VTOC offset
208 RecordOffset tocOffset = getValue(offsets::VTOC_PTR);
209
210 // read VTOC record length
211 RecordLength tocLength = getValue(offsets::VTOC_REC_LEN);
212
213 // read TOC ecc offset
214 ECCOffset tocECCOffset = getValue(offsets::VTOC_ECC_OFF);
215
216 // read TOC ecc length
217 ECCLength tocECCLength = getValue(offsets::VTOC_ECC_LEN);
218
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500219 auto itrToRecord = vpdFile.cbegin();
220 std::advance(itrToRecord, tocOffset);
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600221
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500222 auto iteratorToECC = vpdFile.cbegin();
223 std::advance(iteratorToECC, tocECCOffset);
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600224
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500225 // validate ecc for the record
226 checkECC(itrToRecord, iteratorToECC, tocLength, tocECCLength);
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600227
228 // to get to the record name.
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500229 std::advance(itrToRecord, sizeof(RecordId) + sizeof(RecordSize) +
230 // Skip past the RT keyword, which contains
231 // the record name.
232 lengths::KW_NAME + sizeof(KwSize));
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600233
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500234 std::string recordName(itrToRecord, itrToRecord + lengths::RECORD_NAME);
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600235
236 if ("VTOC" != recordName)
237 {
238 throw std::runtime_error("VTOC record not found");
239 }
240
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600241 // jump to length of PT kwd
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500242 std::advance(itrToRecord, lengths::RECORD_NAME + lengths::KW_NAME);
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600243
244 // Note size of PT
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500245 Byte ptLen = *itrToRecord;
246 std::advance(itrToRecord, 1);
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600247
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500248 checkPTForRecord(itrToRecord, ptLen);
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600249}
250
SunnySrivastava1984d076da82020-03-05 05:33:35 -0600251template <typename T>
252void EditorImpl::makeDbusCall(const std::string& object,
253 const std::string& interface,
254 const std::string& property,
255 const std::variant<T>& data)
256{
257 auto bus = sdbusplus::bus::new_default();
SunnySrivastava1984a7392592020-03-09 10:19:33 -0500258 auto properties =
259 bus.new_method_call(INVENTORY_MANAGER_SERVICE, object.c_str(),
260 "org.freedesktop.DBus.Properties", "Set");
SunnySrivastava1984d076da82020-03-05 05:33:35 -0600261 properties.append(interface);
262 properties.append(property);
263 properties.append(data);
264
265 auto result = bus.call(properties);
266
267 if (result.is_method_error())
268 {
269 throw std::runtime_error("bus call failed");
270 }
271}
272
SunnySrivastava1984b421bfd2020-03-02 08:59:32 -0600273void EditorImpl::processAndUpdateCI(const std::string& objectPath)
274{
275 for (auto& commonInterface : jsonFile["commonInterfaces"].items())
276 {
277 for (auto& ciPropertyList : commonInterface.value().items())
278 {
SunnySrivastava1984d076da82020-03-05 05:33:35 -0600279 if (ciPropertyList.value().type() ==
280 nlohmann::json::value_t::object)
SunnySrivastava1984b421bfd2020-03-02 08:59:32 -0600281 {
SunnySrivastava1984d076da82020-03-05 05:33:35 -0600282 if ((ciPropertyList.value().value("recordName", "") ==
283 thisRecord.recName) &&
284 (ciPropertyList.value().value("keywordName", "") ==
285 thisRecord.recKWd))
286 {
287 std::string kwdData(thisRecord.kwdUpdatedData.begin(),
288 thisRecord.kwdUpdatedData.end());
289
SunnySrivastava1984a7392592020-03-09 10:19:33 -0500290 makeDbusCall<std::string>((INVENTORY_PATH + objectPath),
291 commonInterface.key(),
292 ciPropertyList.key(), kwdData);
SunnySrivastava1984d076da82020-03-05 05:33:35 -0600293 }
SunnySrivastava1984b421bfd2020-03-02 08:59:32 -0600294 }
295 }
296 }
297}
298
299void EditorImpl::processAndUpdateEI(const nlohmann::json& Inventory,
300 const inventory::Path& objPath)
301{
302 for (const auto& extraInterface : Inventory["extraInterfaces"].items())
303 {
304 if (extraInterface.value() != NULL)
305 {
306 for (const auto& eiPropertyList : extraInterface.value().items())
307 {
SunnySrivastava1984d076da82020-03-05 05:33:35 -0600308 if (eiPropertyList.value().type() ==
309 nlohmann::json::value_t::object)
SunnySrivastava1984b421bfd2020-03-02 08:59:32 -0600310 {
SunnySrivastava1984d076da82020-03-05 05:33:35 -0600311 if ((eiPropertyList.value().value("recordName", "") ==
312 thisRecord.recName) &&
313 ((eiPropertyList.value().value("keywordName", "") ==
314 thisRecord.recKWd)))
315 {
316 std::string kwdData(thisRecord.kwdUpdatedData.begin(),
317 thisRecord.kwdUpdatedData.end());
318 makeDbusCall<std::string>(
SunnySrivastava1984a7392592020-03-09 10:19:33 -0500319 (INVENTORY_PATH + objPath), extraInterface.key(),
320 eiPropertyList.key(),
SunnySrivastava1984d076da82020-03-05 05:33:35 -0600321 encodeKeyword(kwdData, eiPropertyList.value().value(
322 "encoding", "")));
323 }
SunnySrivastava1984b421bfd2020-03-02 08:59:32 -0600324 }
325 }
326 }
327 }
328}
329
330void EditorImpl::updateCache()
331{
332 const std::vector<nlohmann::json>& groupEEPROM =
333 jsonFile["frus"][vpdFilePath].get_ref<const nlohmann::json::array_t&>();
334
335 // iterate through all the inventories for this file path
336 for (const auto& singleInventory : groupEEPROM)
337 {
SunnySrivastava1984d076da82020-03-05 05:33:35 -0600338 // by default inherit property is true
339 bool isInherit = true;
340
341 if (singleInventory.find("inherit") != singleInventory.end())
SunnySrivastava1984b421bfd2020-03-02 08:59:32 -0600342 {
SunnySrivastava1984d076da82020-03-05 05:33:35 -0600343 isInherit = singleInventory["inherit"].get<bool>();
344 }
345
346 if (isInherit)
347 {
348 // update com interface
349 makeDbusCall<Binary>(
SunnySrivastava1984a7392592020-03-09 10:19:33 -0500350 (INVENTORY_PATH +
SunnySrivastava1984d076da82020-03-05 05:33:35 -0600351 singleInventory["inventoryPath"].get<std::string>()),
SunnySrivastava1984a7392592020-03-09 10:19:33 -0500352 (IPZ_INTERFACE + (std::string) "." + thisRecord.recName),
SunnySrivastava1984d076da82020-03-05 05:33:35 -0600353 thisRecord.recKWd, thisRecord.kwdUpdatedData);
354
355 // process Common interface
SunnySrivastava1984b421bfd2020-03-02 08:59:32 -0600356 processAndUpdateCI(singleInventory["inventoryPath"]
357 .get_ref<const nlohmann::json::string_t&>());
358 }
359
360 // process extra interfaces
361 processAndUpdateEI(singleInventory,
362 singleInventory["inventoryPath"]
363 .get_ref<const nlohmann::json::string_t&>());
364 }
365}
366
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600367void EditorImpl::updateKeyword(const Binary& kwdData)
368{
369 vpdFileStream.open(vpdFilePath,
370 std::ios::in | std::ios::out | std::ios::binary);
371 if (!vpdFileStream)
372 {
373 throw std::runtime_error("unable to open vpd file to edit");
374 }
375
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500376 Binary completeVPDFile((std::istreambuf_iterator<char>(vpdFileStream)),
377 std::istreambuf_iterator<char>());
378 vpdFile = completeVPDFile;
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600379
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500380 auto iterator = vpdFile.cbegin();
381 std::advance(iterator, IPZ_DATA_START);
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600382
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500383 Byte vpdType = *iterator;
384 if (vpdType == KW_VAL_PAIR_START_TAG)
385 {
386 openpower::vpd::keyword::editor::processHeader(
387 std::move(completeVPDFile));
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600388
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500389 // process VTOC for PTT rkwd
390 readVTOC();
391
392 // check record for keywrod
393 checkRecordForKwd();
394
395 // update the data to the file
396 updateData(kwdData);
397
398 // update the ECC data for the record once data has been updated
399 updateRecordECC();
400
SunnySrivastava1984b421bfd2020-03-02 08:59:32 -0600401 // update the cache once data has been updated
402 updateCache();
403
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500404 return;
405 }
406
407 throw std::runtime_error("Invalid VPD file type");
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600408}
409
410} // namespace editor
411} // namespace manager
412} // namespace vpd
413} // namespace openpower