blob: 898a92550dac9fb0ce914f41c3f47143a13908ec [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
Patrick Williamsc78d8872023-05-10 07:50:56 -05005#include "vpdecc/vpdecc.h"
6
Alpana Kumari414d5ae2021-03-04 21:06:35 +00007#include "common_utility.hpp"
Sunny Srivastava6c71c9d2021-04-15 04:43:54 -05008#include "ibm_vpd_utils.hpp"
SunnySrivastava1984e12b1812020-05-26 02:23:11 -05009#include "ipz_parser.hpp"
10#include "parser_factory.hpp"
Priyanga Ramasamyc99a0b02022-06-08 14:53:39 -050011#include "vpd_exceptions.hpp"
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -060012
Sunny Srivastavaf31a91b2022-06-09 08:11:29 -050013#include <phosphor-logging/elog-errors.hpp>
14#include <xyz/openbmc_project/Common/error.hpp>
15
SunnySrivastava1984e12b1812020-05-26 02:23:11 -050016using namespace openpower::vpd::parser::interface;
17using namespace openpower::vpd::constants;
18using namespace openpower::vpd::parser::factory;
19using namespace openpower::vpd::ipz::parser;
20
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -060021namespace openpower
22{
23namespace vpd
24{
25namespace manager
26{
27namespace editor
28{
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -060029
30void EditorImpl::checkPTForRecord(Binary::const_iterator& iterator,
31 Byte ptLength)
32{
33 // auto iterator = ptRecord.cbegin();
34 auto end = std::next(iterator, ptLength + 1);
35
36 // Look at each entry in the PT keyword for the record name
37 while (iterator < end)
38 {
39 auto stop = std::next(iterator, lengths::RECORD_NAME);
40 std::string record(iterator, stop);
41
42 if (record == thisRecord.recName)
43 {
44 // Skip record name and record type
45 std::advance(iterator, lengths::RECORD_NAME + sizeof(RecordType));
46
47 // Get record offset
48 thisRecord.recOffset = readUInt16LE(iterator);
49
50 // pass the record offset length to read record length
51 std::advance(iterator, lengths::RECORD_OFFSET);
52 thisRecord.recSize = readUInt16LE(iterator);
53
54 std::advance(iterator, lengths::RECORD_LENGTH);
55 thisRecord.recECCoffset = readUInt16LE(iterator);
56
57 ECCLength len;
58 std::advance(iterator, lengths::RECORD_ECC_OFFSET);
59 len = readUInt16LE(iterator);
60 thisRecord.recECCLength = len;
61
62 // once we find the record we don't need to look further
63 return;
64 }
65 else
66 {
67 // Jump the record
68 std::advance(iterator, lengths::RECORD_NAME + sizeof(RecordType) +
69 sizeof(RecordOffset) +
70 sizeof(RecordLength) +
71 sizeof(ECCOffset) + sizeof(ECCLength));
72 }
73 }
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -060074 // imples the record was not found
75 throw std::runtime_error("Record not found");
76}
77
SunnySrivastava19846d8314d2020-05-15 09:34:58 -050078void EditorImpl::updateData(const Binary& kwdData)
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -060079{
80 std::size_t lengthToUpdate = kwdData.size() <= thisRecord.kwdDataLength
81 ? kwdData.size()
82 : thisRecord.kwdDataLength;
83
84 auto iteratorToNewdata = kwdData.cbegin();
85 auto end = iteratorToNewdata;
86 std::advance(end, lengthToUpdate);
87
SunnySrivastava19846d8314d2020-05-15 09:34:58 -050088 // update data in file buffer as it will be needed to update ECC
89 // avoiding extra stream operation here
90 auto iteratorToKWdData = vpdFile.begin();
91 std::advance(iteratorToKWdData, thisRecord.kwDataOffset);
92 std::copy(iteratorToNewdata, end, iteratorToKWdData);
93
SunnySrivastava1984a0d460e2020-06-03 07:49:26 -050094#ifdef ManagerTest
95 auto startItr = vpdFile.begin();
96 std::advance(iteratorToKWdData, thisRecord.kwDataOffset);
97 auto endItr = startItr;
98 std::advance(endItr, thisRecord.kwdDataLength);
99
100 Binary updatedData(startItr, endItr);
101 if (updatedData == kwdData)
102 {
103 throw std::runtime_error("Data updated successfully");
104 }
105#else
106
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500107 // update data in EEPROM as well. As we will not write complete file back
SunnySrivastava1984e12b1812020-05-26 02:23:11 -0500108 vpdFileStream.seekp(startOffset + thisRecord.kwDataOffset, std::ios::beg);
Alpana Kumari920408d2020-05-14 00:07:03 -0500109
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500110 iteratorToNewdata = kwdData.cbegin();
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600111 std::copy(iteratorToNewdata, end,
112 std::ostreambuf_iterator<char>(vpdFileStream));
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500113
114 // get a hold to new data in case encoding is needed
115 thisRecord.kwdUpdatedData.resize(thisRecord.kwdDataLength);
116 auto itrToKWdData = vpdFile.cbegin();
117 std::advance(itrToKWdData, thisRecord.kwDataOffset);
118 auto kwdDataEnd = itrToKWdData;
119 std::advance(kwdDataEnd, thisRecord.kwdDataLength);
120 std::copy(itrToKWdData, kwdDataEnd, thisRecord.kwdUpdatedData.begin());
SunnySrivastava1984a0d460e2020-06-03 07:49:26 -0500121#endif
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600122}
123
124void EditorImpl::checkRecordForKwd()
125{
126 RecordOffset recOffset = thisRecord.recOffset;
127
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500128 // Amount to skip for record ID, size, and the RT keyword
129 constexpr auto skipBeg = sizeof(RecordId) + sizeof(RecordSize) +
130 lengths::KW_NAME + sizeof(KwSize);
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600131
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500132 auto iterator = vpdFile.cbegin();
133 std::advance(iterator, recOffset + skipBeg + lengths::RECORD_NAME);
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600134
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500135 auto end = iterator;
136 std::advance(end, thisRecord.recSize);
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600137 std::size_t dataLength = 0;
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500138
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600139 while (iterator < end)
140 {
141 // Note keyword name
142 std::string kw(iterator, iterator + lengths::KW_NAME);
143
144 // Check if the Keyword starts with '#'
145 char kwNameStart = *iterator;
146 std::advance(iterator, lengths::KW_NAME);
147
148 // if keyword starts with #
149 if (POUND_KW == kwNameStart)
150 {
151 // Note existing keyword data length
152 dataLength = readUInt16LE(iterator);
153
154 // Jump past 2Byte keyword length + data
155 std::advance(iterator, sizeof(PoundKwSize));
156 }
157 else
158 {
159 // Note existing keyword data length
160 dataLength = *iterator;
161
162 // Jump past keyword length and data
163 std::advance(iterator, sizeof(KwSize));
164 }
165
166 if (thisRecord.recKWd == kw)
167 {
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500168 thisRecord.kwDataOffset = std::distance(vpdFile.cbegin(), iterator);
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600169 thisRecord.kwdDataLength = dataLength;
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600170 return;
171 }
172
173 // jump the data of current kwd to point to next kwd name
174 std::advance(iterator, dataLength);
175 }
176
177 throw std::runtime_error("Keyword not found");
178}
179
180void EditorImpl::updateRecordECC()
181{
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500182 auto itrToRecordData = vpdFile.cbegin();
183 std::advance(itrToRecordData, thisRecord.recOffset);
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600184
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500185 auto itrToRecordECC = vpdFile.cbegin();
186 std::advance(itrToRecordECC, thisRecord.recECCoffset);
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600187
188 auto l_status = vpdecc_create_ecc(
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500189 const_cast<uint8_t*>(&itrToRecordData[0]), thisRecord.recSize,
190 const_cast<uint8_t*>(&itrToRecordECC[0]), &thisRecord.recECCLength);
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600191 if (l_status != VPD_ECC_OK)
192 {
193 throw std::runtime_error("Ecc update failed");
194 }
195
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500196 auto end = itrToRecordECC;
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600197 std::advance(end, thisRecord.recECCLength);
198
SunnySrivastava1984a0d460e2020-06-03 07:49:26 -0500199#ifndef ManagerTest
SunnySrivastava1984e12b1812020-05-26 02:23:11 -0500200 vpdFileStream.seekp(startOffset + thisRecord.recECCoffset, std::ios::beg);
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500201 std::copy(itrToRecordECC, end,
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600202 std::ostreambuf_iterator<char>(vpdFileStream));
SunnySrivastava1984a0d460e2020-06-03 07:49:26 -0500203#endif
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600204}
205
206auto EditorImpl::getValue(offsets::Offsets offset)
207{
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500208 auto itr = vpdFile.cbegin();
209 std::advance(itr, offset);
210 LE2ByteData lowByte = *itr;
211 LE2ByteData highByte = *(itr + 1);
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600212 lowByte |= (highByte << 8);
213
214 return lowByte;
215}
216
girik18bb9852022-11-16 05:48:13 -0600217void EditorImpl::checkRecordData()
218{
219 auto itrToRecordData = vpdFile.cbegin();
220 std::advance(itrToRecordData, thisRecord.recOffset);
221
222 auto itrToRecordECC = vpdFile.cbegin();
223 std::advance(itrToRecordECC, thisRecord.recECCoffset);
224
225 checkECC(itrToRecordData, itrToRecordECC, thisRecord.recSize,
226 thisRecord.recECCLength);
227}
228
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500229void EditorImpl::checkECC(Binary::const_iterator& itrToRecData,
230 Binary::const_iterator& itrToECCData,
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600231 RecordLength recLength, ECCLength eccLength)
232{
233 auto l_status =
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500234 vpdecc_check_data(const_cast<uint8_t*>(&itrToRecData[0]), recLength,
235 const_cast<uint8_t*>(&itrToECCData[0]), eccLength);
236
girik18bb9852022-11-16 05:48:13 -0600237 if (l_status == VPD_ECC_CORRECTABLE_DATA)
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600238 {
girik18bb9852022-11-16 05:48:13 -0600239 try
240 {
241 if (vpdFileStream.is_open())
242 {
243 vpdFileStream.seekp(startOffset + thisRecord.recOffset,
244 std::ios::beg);
245 auto end = itrToRecData;
246 std::advance(end, recLength);
247 std::copy(itrToRecData, end,
248 std::ostreambuf_iterator<char>(vpdFileStream));
249 }
250 else
251 {
252 throw std::runtime_error("Ecc correction failed");
253 }
254 }
255 catch (const std::fstream::failure& e)
256 {
257 std::cout << "Error while operating on file with exception";
258 throw std::runtime_error("Ecc correction failed");
259 }
260 }
261 else if (l_status != VPD_ECC_OK)
262 {
263 throw std::runtime_error("Ecc check failed");
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600264 }
265}
266
267void EditorImpl::readVTOC()
268{
269 // read VTOC offset
270 RecordOffset tocOffset = getValue(offsets::VTOC_PTR);
271
272 // read VTOC record length
273 RecordLength tocLength = getValue(offsets::VTOC_REC_LEN);
274
275 // read TOC ecc offset
276 ECCOffset tocECCOffset = getValue(offsets::VTOC_ECC_OFF);
277
278 // read TOC ecc length
279 ECCLength tocECCLength = getValue(offsets::VTOC_ECC_LEN);
280
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500281 auto itrToRecord = vpdFile.cbegin();
282 std::advance(itrToRecord, tocOffset);
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600283
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500284 auto iteratorToECC = vpdFile.cbegin();
285 std::advance(iteratorToECC, tocECCOffset);
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600286
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500287 // validate ecc for the record
288 checkECC(itrToRecord, iteratorToECC, tocLength, tocECCLength);
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600289
290 // to get to the record name.
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500291 std::advance(itrToRecord, sizeof(RecordId) + sizeof(RecordSize) +
292 // Skip past the RT keyword, which contains
293 // the record name.
294 lengths::KW_NAME + sizeof(KwSize));
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600295
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500296 std::string recordName(itrToRecord, itrToRecord + lengths::RECORD_NAME);
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600297
298 if ("VTOC" != recordName)
299 {
300 throw std::runtime_error("VTOC record not found");
301 }
302
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600303 // jump to length of PT kwd
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500304 std::advance(itrToRecord, lengths::RECORD_NAME + lengths::KW_NAME);
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600305
306 // Note size of PT
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500307 Byte ptLen = *itrToRecord;
308 std::advance(itrToRecord, 1);
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600309
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500310 checkPTForRecord(itrToRecord, ptLen);
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600311}
312
SunnySrivastava1984d076da82020-03-05 05:33:35 -0600313template <typename T>
314void EditorImpl::makeDbusCall(const std::string& object,
315 const std::string& interface,
316 const std::string& property,
317 const std::variant<T>& data)
318{
319 auto bus = sdbusplus::bus::new_default();
SunnySrivastava1984a7392592020-03-09 10:19:33 -0500320 auto properties =
321 bus.new_method_call(INVENTORY_MANAGER_SERVICE, object.c_str(),
322 "org.freedesktop.DBus.Properties", "Set");
SunnySrivastava1984d076da82020-03-05 05:33:35 -0600323 properties.append(interface);
324 properties.append(property);
325 properties.append(data);
326
327 auto result = bus.call(properties);
328
329 if (result.is_method_error())
330 {
331 throw std::runtime_error("bus call failed");
332 }
333}
334
SunnySrivastava1984b421bfd2020-03-02 08:59:32 -0600335void EditorImpl::processAndUpdateCI(const std::string& objectPath)
336{
Alpana Kumari414d5ae2021-03-04 21:06:35 +0000337 inventory::ObjectMap objects;
SunnySrivastava1984b421bfd2020-03-02 08:59:32 -0600338 for (auto& commonInterface : jsonFile["commonInterfaces"].items())
339 {
340 for (auto& ciPropertyList : commonInterface.value().items())
341 {
SunnySrivastava1984d076da82020-03-05 05:33:35 -0600342 if (ciPropertyList.value().type() ==
343 nlohmann::json::value_t::object)
SunnySrivastava1984b421bfd2020-03-02 08:59:32 -0600344 {
SunnySrivastava1984d076da82020-03-05 05:33:35 -0600345 if ((ciPropertyList.value().value("recordName", "") ==
346 thisRecord.recName) &&
347 (ciPropertyList.value().value("keywordName", "") ==
348 thisRecord.recKWd))
349 {
Alpana Kumari414d5ae2021-03-04 21:06:35 +0000350 inventory::PropertyMap prop;
351 inventory::InterfaceMap interfaces;
SunnySrivastava1984d076da82020-03-05 05:33:35 -0600352 std::string kwdData(thisRecord.kwdUpdatedData.begin(),
353 thisRecord.kwdUpdatedData.end());
354
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500355 prop.emplace(ciPropertyList.key(), std::move(kwdData));
356 interfaces.emplace(commonInterface.key(), std::move(prop));
357 objects.emplace(objectPath, std::move(interfaces));
SunnySrivastava1984d076da82020-03-05 05:33:35 -0600358 }
SunnySrivastava1984b421bfd2020-03-02 08:59:32 -0600359 }
360 }
361 }
Alpana Kumari414d5ae2021-03-04 21:06:35 +0000362 // Notify PIM
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500363 common::utility::callPIM(std::move(objects));
SunnySrivastava1984b421bfd2020-03-02 08:59:32 -0600364}
365
366void EditorImpl::processAndUpdateEI(const nlohmann::json& Inventory,
367 const inventory::Path& objPath)
368{
Alpana Kumari414d5ae2021-03-04 21:06:35 +0000369 inventory::ObjectMap objects;
SunnySrivastava1984b421bfd2020-03-02 08:59:32 -0600370 for (const auto& extraInterface : Inventory["extraInterfaces"].items())
371 {
372 if (extraInterface.value() != NULL)
373 {
374 for (const auto& eiPropertyList : extraInterface.value().items())
375 {
SunnySrivastava1984d076da82020-03-05 05:33:35 -0600376 if (eiPropertyList.value().type() ==
377 nlohmann::json::value_t::object)
SunnySrivastava1984b421bfd2020-03-02 08:59:32 -0600378 {
SunnySrivastava1984d076da82020-03-05 05:33:35 -0600379 if ((eiPropertyList.value().value("recordName", "") ==
380 thisRecord.recName) &&
381 ((eiPropertyList.value().value("keywordName", "") ==
382 thisRecord.recKWd)))
383 {
Alpana Kumari414d5ae2021-03-04 21:06:35 +0000384 inventory::PropertyMap prop;
385 inventory::InterfaceMap interfaces;
SunnySrivastava1984d076da82020-03-05 05:33:35 -0600386 std::string kwdData(thisRecord.kwdUpdatedData.begin(),
387 thisRecord.kwdUpdatedData.end());
Alpana Kumari414d5ae2021-03-04 21:06:35 +0000388 encodeKeyword(kwdData, eiPropertyList.value().value(
389 "encoding", ""));
390
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500391 prop.emplace(eiPropertyList.key(), std::move(kwdData));
392 interfaces.emplace(extraInterface.key(),
393 std::move(prop));
394 objects.emplace(objPath, std::move(interfaces));
SunnySrivastava1984d076da82020-03-05 05:33:35 -0600395 }
SunnySrivastava1984b421bfd2020-03-02 08:59:32 -0600396 }
397 }
398 }
399 }
Alpana Kumari414d5ae2021-03-04 21:06:35 +0000400 // Notify PIM
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500401 common::utility::callPIM(std::move(objects));
SunnySrivastava1984b421bfd2020-03-02 08:59:32 -0600402}
403
404void EditorImpl::updateCache()
405{
406 const std::vector<nlohmann::json>& groupEEPROM =
407 jsonFile["frus"][vpdFilePath].get_ref<const nlohmann::json::array_t&>();
408
Alpana Kumari414d5ae2021-03-04 21:06:35 +0000409 inventory::ObjectMap objects;
SunnySrivastava1984b421bfd2020-03-02 08:59:32 -0600410 // iterate through all the inventories for this file path
411 for (const auto& singleInventory : groupEEPROM)
412 {
Alpana Kumari414d5ae2021-03-04 21:06:35 +0000413 inventory::PropertyMap prop;
414 inventory::InterfaceMap interfaces;
SunnySrivastava1984d076da82020-03-05 05:33:35 -0600415 // by default inherit property is true
416 bool isInherit = true;
417
418 if (singleInventory.find("inherit") != singleInventory.end())
SunnySrivastava1984b421bfd2020-03-02 08:59:32 -0600419 {
SunnySrivastava1984d076da82020-03-05 05:33:35 -0600420 isInherit = singleInventory["inherit"].get<bool>();
421 }
422
423 if (isInherit)
424 {
Priyanga Ramasamy5629fbc2023-03-01 08:17:19 -0600425 prop.emplace(getDbusNameForThisKw(thisRecord.recKWd),
426 thisRecord.kwdUpdatedData);
Santosh Puranik32c46502022-02-10 08:55:07 +0530427 interfaces.emplace(
428 (IPZ_INTERFACE + (std::string) "." + thisRecord.recName),
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500429 std::move(prop));
Santosh Puranik32c46502022-02-10 08:55:07 +0530430 objects.emplace(
431 (singleInventory["inventoryPath"].get<std::string>()),
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500432 std::move(interfaces));
SunnySrivastava1984d076da82020-03-05 05:33:35 -0600433
434 // process Common interface
SunnySrivastava1984b421bfd2020-03-02 08:59:32 -0600435 processAndUpdateCI(singleInventory["inventoryPath"]
436 .get_ref<const nlohmann::json::string_t&>());
437 }
438
Santosh Puranik32c46502022-02-10 08:55:07 +0530439 // process extra interfaces
440 processAndUpdateEI(singleInventory,
441 singleInventory["inventoryPath"]
442 .get_ref<const nlohmann::json::string_t&>());
Sunny Srivastava26d6c142021-11-03 15:19:02 -0500443
444 // check if we need to copy some specific records in this case.
445 if (singleInventory.find("copyRecords") != singleInventory.end())
446 {
447 if (find(singleInventory["copyRecords"].begin(),
448 singleInventory["copyRecords"].end(),
449 thisRecord.recName) !=
450 singleInventory["copyRecords"].end())
451 {
452 prop.emplace(thisRecord.recKWd, thisRecord.kwdUpdatedData);
453 interfaces.emplace(
454 (IPZ_INTERFACE + std::string{"."} + thisRecord.recName),
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500455 std::move(prop));
Sunny Srivastava26d6c142021-11-03 15:19:02 -0500456 objects.emplace(
457 (singleInventory["inventoryPath"].get<std::string>()),
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500458 std::move(interfaces));
Sunny Srivastava26d6c142021-11-03 15:19:02 -0500459 }
460 }
SunnySrivastava1984b421bfd2020-03-02 08:59:32 -0600461 }
Alpana Kumari414d5ae2021-03-04 21:06:35 +0000462 // Notify PIM
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500463 common::utility::callPIM(std::move(objects));
SunnySrivastava1984b421bfd2020-03-02 08:59:32 -0600464}
465
SunnySrivastava198443306542020-04-01 02:50:20 -0500466void EditorImpl::expandLocationCode(const std::string& locationCodeType)
467{
468 std::string propertyFCorTM{};
469 std::string propertySE{};
470
471 if (locationCodeType == "fcs")
472 {
Patrick Williamsc78d8872023-05-10 07:50:56 -0500473 propertyFCorTM = readBusProperty(SYSTEM_OBJECT, "com.ibm.ipzvpd.VCEN",
474 "FC");
475 propertySE = readBusProperty(SYSTEM_OBJECT, "com.ibm.ipzvpd.VCEN",
476 "SE");
SunnySrivastava198443306542020-04-01 02:50:20 -0500477 }
478 else if (locationCodeType == "mts")
479 {
Patrick Williamsc78d8872023-05-10 07:50:56 -0500480 propertyFCorTM = readBusProperty(SYSTEM_OBJECT, "com.ibm.ipzvpd.VSYS",
481 "TM");
482 propertySE = readBusProperty(SYSTEM_OBJECT, "com.ibm.ipzvpd.VSYS",
483 "SE");
SunnySrivastava198443306542020-04-01 02:50:20 -0500484 }
485
486 const nlohmann::json& groupFRUS =
487 jsonFile["frus"].get_ref<const nlohmann::json::object_t&>();
Alpana Kumari414d5ae2021-03-04 21:06:35 +0000488 inventory::ObjectMap objects;
489
SunnySrivastava198443306542020-04-01 02:50:20 -0500490 for (const auto& itemFRUS : groupFRUS.items())
491 {
492 const std::vector<nlohmann::json>& groupEEPROM =
493 itemFRUS.value().get_ref<const nlohmann::json::array_t&>();
494 for (const auto& itemEEPROM : groupEEPROM)
495 {
Alpana Kumari414d5ae2021-03-04 21:06:35 +0000496 inventory::PropertyMap prop;
497 inventory::InterfaceMap interfaces;
498 const auto& objectPath = itemEEPROM["inventoryPath"];
499 sdbusplus::message::object_path object(objectPath);
500
SunnySrivastava198443306542020-04-01 02:50:20 -0500501 // check if the given item implements location code interface
Alpana Kumari414d5ae2021-03-04 21:06:35 +0000502 if (itemEEPROM["extraInterfaces"].find(IBM_LOCATION_CODE_INF) !=
SunnySrivastava198443306542020-04-01 02:50:20 -0500503 itemEEPROM["extraInterfaces"].end())
504 {
505 const std::string& unexpandedLocationCode =
Alpana Kumari414d5ae2021-03-04 21:06:35 +0000506 itemEEPROM["extraInterfaces"][IBM_LOCATION_CODE_INF]
SunnySrivastava198443306542020-04-01 02:50:20 -0500507 ["LocationCode"]
508 .get_ref<const nlohmann::json::string_t&>();
509 std::size_t idx = unexpandedLocationCode.find(locationCodeType);
510 if (idx != std::string::npos)
511 {
Alpana Kumari414d5ae2021-03-04 21:06:35 +0000512 std::string expandedLocationCode(unexpandedLocationCode);
SunnySrivastava198443306542020-04-01 02:50:20 -0500513
514 if (locationCodeType == "fcs")
515 {
Alpana Kumari414d5ae2021-03-04 21:06:35 +0000516 expandedLocationCode.replace(
SunnySrivastava198443306542020-04-01 02:50:20 -0500517 idx, 3,
518 propertyFCorTM.substr(0, 4) + ".ND0." + propertySE);
519 }
520 else if (locationCodeType == "mts")
521 {
522 std::replace(propertyFCorTM.begin(),
523 propertyFCorTM.end(), '-', '.');
Alpana Kumari414d5ae2021-03-04 21:06:35 +0000524 expandedLocationCode.replace(
SunnySrivastava198443306542020-04-01 02:50:20 -0500525 idx, 3, propertyFCorTM + "." + propertySE);
526 }
527
Alpana Kumari414d5ae2021-03-04 21:06:35 +0000528 // update the DBUS interface COM as well as XYZ path
529 prop.emplace("LocationCode", expandedLocationCode);
530 // TODO depricate this com.ibm interface later
531 interfaces.emplace(IBM_LOCATION_CODE_INF, prop);
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500532 interfaces.emplace(XYZ_LOCATION_CODE_INF, std::move(prop));
SunnySrivastava198443306542020-04-01 02:50:20 -0500533 }
534 }
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500535 objects.emplace(std::move(object), std::move(interfaces));
SunnySrivastava198443306542020-04-01 02:50:20 -0500536 }
537 }
Alpana Kumari414d5ae2021-03-04 21:06:35 +0000538 // Notify PIM
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500539 common::utility::callPIM(std::move(objects));
SunnySrivastava198443306542020-04-01 02:50:20 -0500540}
541
Sunny Srivastavaf31a91b2022-06-09 08:11:29 -0500542#ifndef ManagerTest
543static void enableRebootGuard()
544{
545 try
546 {
547 auto bus = sdbusplus::bus::new_default();
548 auto method = bus.new_method_call(
549 "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
550 "org.freedesktop.systemd1.Manager", "StartUnit");
551 method.append("reboot-guard-enable.service", "replace");
552 bus.call_noreply(method);
553 }
Patrick Williams7a975f02022-12-07 03:19:53 -0600554 catch (const sdbusplus::exception_t& e)
Sunny Srivastavaf31a91b2022-06-09 08:11:29 -0500555 {
556 std::string errMsg =
557 "Bus call to enable BMC reboot failed for reason: ";
558 errMsg += e.what();
559
560 throw std::runtime_error(errMsg);
561 }
562}
563
564static void disableRebootGuard()
565{
566 try
567 {
568 auto bus = sdbusplus::bus::new_default();
569 auto method = bus.new_method_call(
570 "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
571 "org.freedesktop.systemd1.Manager", "StartUnit");
572 method.append("reboot-guard-disable.service", "replace");
573 bus.call_noreply(method);
574 }
Patrick Williams7a975f02022-12-07 03:19:53 -0600575 catch (const sdbusplus::exception_t& e)
Sunny Srivastavaf31a91b2022-06-09 08:11:29 -0500576 {
577 using namespace phosphor::logging;
578 using InternalFailure =
579 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
580
581 std::string errMsg =
582 "Bus call to disable BMC reboot failed for reason: ";
583 errMsg += e.what();
584
585 log<level::ERR>("Disable boot guard failed");
586 elog<InternalFailure>();
587
588 throw std::runtime_error(errMsg);
589 }
590}
591#endif
592
Santosh Puranika0b23912022-02-10 13:37:09 +0530593void EditorImpl::updateKeyword(const Binary& kwdData, uint32_t offset,
594 const bool& updCache)
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600595{
Sunny Srivastavaf31a91b2022-06-09 08:11:29 -0500596 try
597 {
598 startOffset = offset;
SunnySrivastava1984a0d460e2020-06-03 07:49:26 -0500599#ifndef ManagerTest
Sunny Srivastavaf31a91b2022-06-09 08:11:29 -0500600 // Restrict BMC from rebooting when VPD is being written. This will
601 // prevent any data/ECC corruption in case BMC reboots while VPD update.
602 enableRebootGuard();
SunnySrivastava1984a0d460e2020-06-03 07:49:26 -0500603
Sunny Srivastavaf31a91b2022-06-09 08:11:29 -0500604 Binary completeVPDFile;
jinuthomas45d54972023-07-03 04:36:29 -0500605 vpdFileStream.exceptions(std::ifstream::badbit |
606 std::ifstream::failbit);
607 try
608 {
609 vpdFileStream.open(vpdFilePath,
610 std::ios::in | std::ios::out | std::ios::binary);
Priyanga Ramasamy4170bda2023-07-19 09:25:36 +0000611
612 auto vpdFileSize = std::min(std::filesystem::file_size(vpdFilePath),
613 MAX_VPD_SIZE);
614 if (vpdFileSize == 0)
615 {
616 std::cerr << "File size is 0 for " << vpdFilePath << std::endl;
617 throw std::runtime_error("File size is 0.");
618 }
619
620 completeVPDFile.resize(vpdFileSize);
jinuthomas45d54972023-07-03 04:36:29 -0500621 vpdFileStream.seekg(startOffset, std::ios_base::cur);
622 vpdFileStream.read(reinterpret_cast<char*>(&completeVPDFile[0]),
Priyanga Ramasamy4170bda2023-07-19 09:25:36 +0000623 vpdFileSize);
jinuthomas45d54972023-07-03 04:36:29 -0500624 vpdFileStream.clear(std::ios_base::eofbit);
625 }
Priyanga Ramasamy4170bda2023-07-19 09:25:36 +0000626 catch (const std::system_error& fail)
jinuthomas45d54972023-07-03 04:36:29 -0500627 {
628 std::cerr << "Exception in file handling [" << vpdFilePath
629 << "] error : " << fail.what();
630 std::cerr << "Stream file size = " << vpdFileStream.gcount()
631 << std::endl;
632 throw;
633 }
Sunny Srivastavaf31a91b2022-06-09 08:11:29 -0500634 vpdFile = completeVPDFile;
635
636 if (objPath.empty() &&
637 jsonFile["frus"].find(vpdFilePath) != jsonFile["frus"].end())
638 {
639 objPath = jsonFile["frus"][vpdFilePath][0]["inventoryPath"]
640 .get_ref<const nlohmann::json::string_t&>();
641 }
Alpana Kumari920408d2020-05-14 00:07:03 -0500642
SunnySrivastava1984a0d460e2020-06-03 07:49:26 -0500643#else
Alpana Kumari920408d2020-05-14 00:07:03 -0500644
Sunny Srivastavaf31a91b2022-06-09 08:11:29 -0500645 Binary completeVPDFile = vpdFile;
Alpana Kumari920408d2020-05-14 00:07:03 -0500646
SunnySrivastava1984a0d460e2020-06-03 07:49:26 -0500647#endif
Sunny Srivastavaf31a91b2022-06-09 08:11:29 -0500648 if (vpdFile.empty())
SunnySrivastava1984e12b1812020-05-26 02:23:11 -0500649 {
Sunny Srivastavaf31a91b2022-06-09 08:11:29 -0500650 throw std::runtime_error("Invalid File");
SunnySrivastava1984e12b1812020-05-26 02:23:11 -0500651 }
Sunny Srivastavaf31a91b2022-06-09 08:11:29 -0500652 auto iterator = vpdFile.cbegin();
653 std::advance(iterator, IPZ_DATA_START);
654
655 Byte vpdType = *iterator;
656 if (vpdType == KW_VAL_PAIR_START_TAG)
SunnySrivastava1984e12b1812020-05-26 02:23:11 -0500657 {
Sunny Srivastavaf31a91b2022-06-09 08:11:29 -0500658 // objPath should be empty only in case of test run.
girik18bb9852022-11-16 05:48:13 -0600659 ParserInterface* Iparser = ParserFactory::getParser(
660 completeVPDFile, objPath, vpdFilePath, startOffset);
Sunny Srivastavaf31a91b2022-06-09 08:11:29 -0500661 IpzVpdParser* ipzParser = dynamic_cast<IpzVpdParser*>(Iparser);
662
663 try
SunnySrivastava1984e12b1812020-05-26 02:23:11 -0500664 {
Sunny Srivastavaf31a91b2022-06-09 08:11:29 -0500665 if (ipzParser == nullptr)
666 {
667 throw std::runtime_error("Invalid cast");
668 }
669
670 ipzParser->processHeader();
SunnySrivastava1984e12b1812020-05-26 02:23:11 -0500671 delete ipzParser;
Sunny Srivastavaf31a91b2022-06-09 08:11:29 -0500672 ipzParser = nullptr;
673 // ParserFactory::freeParser(Iparser);
674
675 // process VTOC for PTT rkwd
676 readVTOC();
677
678 // check record for keywrod
679 checkRecordForKwd();
680
girik18bb9852022-11-16 05:48:13 -0600681 // Check Data before updating
682 checkRecordData();
683
Sunny Srivastavaf31a91b2022-06-09 08:11:29 -0500684 // update the data to the file
685 updateData(kwdData);
686
687 // update the ECC data for the record once data has been updated
688 updateRecordECC();
689
690 if (updCache)
691 {
692#ifndef ManagerTest
693 // update the cache once data has been updated
694 updateCache();
695#endif
696 }
SunnySrivastava1984e12b1812020-05-26 02:23:11 -0500697 }
Sunny Srivastavaf31a91b2022-06-09 08:11:29 -0500698 catch (const std::exception& e)
699 {
700 if (ipzParser != nullptr)
701 {
702 delete ipzParser;
703 }
704 throw std::runtime_error(e.what());
705 }
706
707#ifndef ManagerTest
708 // Once VPD data and Ecc update is done, disable BMC boot guard.
709 disableRebootGuard();
710#endif
711
712 return;
SunnySrivastava1984e12b1812020-05-26 02:23:11 -0500713 }
Sunny Srivastavaf31a91b2022-06-09 08:11:29 -0500714 else
715 {
716 throw openpower::vpd::exceptions::VpdDataException(
717 "Could not find start tag in VPD " + vpdFilePath);
718 }
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500719 }
Sunny Srivastavaf31a91b2022-06-09 08:11:29 -0500720 catch (const std::exception& e)
Priyanga Ramasamyc99a0b02022-06-08 14:53:39 -0500721 {
Sunny Srivastavaf31a91b2022-06-09 08:11:29 -0500722#ifndef ManagerTest
723 // Disable reboot guard.
724 disableRebootGuard();
725#endif
726
727 throw std::runtime_error(e.what());
Priyanga Ramasamyc99a0b02022-06-08 14:53:39 -0500728 }
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600729}
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600730} // namespace editor
731} // namespace manager
732} // namespace vpd
Patrick Williamsc78d8872023-05-10 07:50:56 -0500733} // namespace openpower