blob: 3926c754efe151fc078882285c80ae088e6e0b68 [file] [log] [blame]
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +05301#include "vpd_tool_impl.hpp"
2
Priyanga Ramasamy38031312021-10-07 16:39:13 -05003#include "impl.hpp"
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -05004#include "parser_factory.hpp"
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +05305#include "vpd_exceptions.hpp"
6
PriyangaRamasamycdf943c2020-03-18 02:25:30 +05307#include <cstdlib>
8#include <filesystem>
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +05309#include <iostream>
10#include <sdbusplus/bus.hpp>
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +053011#include <variant>
12#include <vector>
13
14using namespace std;
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +053015using namespace openpower::vpd;
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +053016using namespace inventory;
17using namespace openpower::vpd::manager::editor;
PriyangaRamasamycdf943c2020-03-18 02:25:30 +053018namespace fs = std::filesystem;
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +053019using json = nlohmann::json;
20using namespace openpower::vpd::exceptions;
Priyanga Ramasamy38031312021-10-07 16:39:13 -050021using namespace openpower::vpd::parser;
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -050022using namespace openpower::vpd::parser::factory;
23using namespace openpower::vpd::parser::interface;
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +053024
Priyanga Ramasamy6d5e7342022-10-14 07:17:25 -050025static void
26 getVPDInMap(const std::string& vpdPath,
27 std::unordered_map<std::string, DbusPropertyMap>& vpdMap,
28 json& js, const std::string& invPath)
29{
30 auto jsonToParse = INVENTORY_JSON_DEFAULT;
31 if (fs::exists(INVENTORY_JSON_SYM_LINK))
32 {
33 jsonToParse = INVENTORY_JSON_SYM_LINK;
34 }
35
36 std::ifstream inventoryJson(jsonToParse);
37 if (!inventoryJson)
38 {
39 throw std::runtime_error("VPD JSON file not found");
40 }
41
42 try
43 {
44 js = json::parse(inventoryJson);
45 }
46 catch (const json::parse_error& ex)
47 {
48 throw std::runtime_error("VPD JSON parsing failed");
49 }
50
51 Binary vpdVector{};
52
53 vpdVector = getVpdDataInVector(js, constants::systemVpdFilePath);
54 ParserInterface* parser = ParserFactory::getParser(vpdVector, invPath);
55 auto parseResult = parser->parse();
56 ParserFactory::freeParser(parser);
57
58 if (auto pVal = std::get_if<Store>(&parseResult))
59 {
60 vpdMap = pVal->getVpdMap();
61 }
62 else
63 {
64 std::string err =
65 vpdPath + " is not of type IPZ VPD. Unable to parse the VPD.";
66 throw std::runtime_error(err);
67 }
68}
69
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +053070Binary VpdTool::toBinary(const std::string& value)
71{
72 Binary val{};
73 if (value.find("0x") == string::npos)
74 {
75 val.assign(value.begin(), value.end());
76 }
77 else if (value.find("0x") != string::npos)
78 {
79 stringstream ss;
80 ss.str(value.substr(2));
81 string byteStr{};
82
Priyanga Ramasamyec912e62021-12-15 22:47:51 -060083 if (value.length() % 2 != 0)
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +053084 {
Priyanga Ramasamyec912e62021-12-15 22:47:51 -060085 throw runtime_error(
86 "VPD-TOOL write option accepts 2 digit hex numbers. (Eg. 0x1 "
87 "should be given as 0x01). Aborting the write operation.");
88 }
89
90 if (value.find_first_not_of("0123456789abcdefABCDEF", 2) !=
91 std::string::npos)
92 {
93 throw runtime_error("Provide a valid hexadecimal input.");
94 }
95
96 while (ss >> setw(2) >> byteStr)
97 {
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +053098 uint8_t byte = strtoul(byteStr.c_str(), nullptr, 16);
99
100 val.push_back(byte);
101 }
102 }
103
104 else
105 {
106 throw runtime_error("The value to be updated should be either in ascii "
107 "or in hex. Refer --help option");
108 }
109 return val;
110}
PriyangaRamasamycdf943c2020-03-18 02:25:30 +0530111
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600112void VpdTool::printReturnCode(int returnCode)
113{
114 if (returnCode)
115 {
116 cout << "\n Command failed with the return code " << returnCode
117 << ". Continuing the execution. " << endl;
118 }
119}
120
PriyangaRamasamycdf943c2020-03-18 02:25:30 +0530121void VpdTool::eraseInventoryPath(string& fru)
122{
123 // Power supply frupath comes with INVENTORY_PATH appended in prefix.
124 // Stripping it off inorder to avoid INVENTORY_PATH duplication
125 // during getVINIProperties() execution.
126 fru.erase(0, sizeof(INVENTORY_PATH) - 1);
127}
128
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530129void VpdTool::debugger(json output)
130{
131 cout << output.dump(4) << '\n';
132}
133
134auto VpdTool::makeDBusCall(const string& objectName, const string& interface,
135 const string& kw)
136{
137 auto bus = sdbusplus::bus::new_default();
138 auto properties =
139 bus.new_method_call(INVENTORY_MANAGER_SERVICE, objectName.c_str(),
140 "org.freedesktop.DBus.Properties", "Get");
141 properties.append(interface);
142 properties.append(kw);
143 auto result = bus.call(properties);
144
145 if (result.is_method_error())
146 {
147 throw runtime_error("Get api failed");
148 }
149 return result;
150}
151
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500152json VpdTool::getVINIProperties(string invPath)
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530153{
154 variant<Binary> response;
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530155 json kwVal = json::object({});
156
157 vector<string> keyword{"CC", "SN", "PN", "FN", "DR"};
158 string interface = "com.ibm.ipzvpd.VINI";
PriyangaRamasamycdf943c2020-03-18 02:25:30 +0530159 string objectName = {};
160
161 if (invPath.find(INVENTORY_PATH) != string::npos)
162 {
163 objectName = invPath;
164 eraseInventoryPath(invPath);
165 }
166 else
167 {
168 objectName = INVENTORY_PATH + invPath;
169 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530170 for (string kw : keyword)
171 {
172 try
173 {
174 makeDBusCall(objectName, interface, kw).read(response);
175
176 if (auto vec = get_if<Binary>(&response))
177 {
PriyangaRamasamy887a42a2020-09-03 00:33:57 +0530178 string printableVal = getPrintableValue(*vec);
179 kwVal.emplace(kw, printableVal);
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530180 }
181 }
Patrick Williams2eb01762022-07-22 19:26:56 -0500182 catch (const sdbusplus::exception_t& e)
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530183 {
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500184 if (string(e.name()) ==
185 string("org.freedesktop.DBus.Error.UnknownObject"))
186 {
187 kwVal.emplace(invPath, json::object({}));
188 objFound = false;
189 break;
190 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530191 }
192 }
193
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500194 return kwVal;
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530195}
196
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500197void VpdTool::getExtraInterfaceProperties(const string& invPath,
198 const string& extraInterface,
199 const json& prop, json& output)
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530200{
201 variant<string> response;
202
203 string objectName = INVENTORY_PATH + invPath;
204
205 for (const auto& itProp : prop.items())
206 {
207 string kw = itProp.key();
208 try
209 {
210 makeDBusCall(objectName, extraInterface, kw).read(response);
211
212 if (auto str = get_if<string>(&response))
213 {
214 output.emplace(kw, *str);
215 }
216 }
Patrick Williams2eb01762022-07-22 19:26:56 -0500217 catch (const sdbusplus::exception_t& e)
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530218 {
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500219 if (std::string(e.name()) ==
220 std::string("org.freedesktop.DBus.Error.UnknownObject"))
221 {
222 objFound = false;
223 break;
224 }
225 else if (std::string(e.name()) ==
226 std::string("org.freedesktop.DBus.Error.UnknownProperty"))
227 {
228 output.emplace(kw, "");
229 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530230 }
231 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530232}
233
234json VpdTool::interfaceDecider(json& itemEEPROM)
235{
236 if (itemEEPROM.find("inventoryPath") == itemEEPROM.end())
237 {
238 throw runtime_error("Inventory Path not found");
239 }
240
241 if (itemEEPROM.find("extraInterfaces") == itemEEPROM.end())
242 {
243 throw runtime_error("Extra Interfaces not found");
244 }
245
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500246 json subOutput = json::object({});
Alpana Kumarib6965f12020-06-01 00:32:21 -0500247 fruType = "FRU";
248
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500249 json j;
250 objFound = true;
251 string invPath = itemEEPROM.at("inventoryPath");
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530252
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500253 j = getVINIProperties(invPath);
254
255 if (objFound)
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530256 {
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500257 subOutput.insert(j.begin(), j.end());
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530258 json js;
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500259 if (itemEEPROM.find("type") != itemEEPROM.end())
260 {
261 fruType = itemEEPROM.at("type");
262 }
263 js.emplace("TYPE", fruType);
264
265 if (invPath.find("powersupply") != string::npos)
266 {
267 js.emplace("type", POWER_SUPPLY_TYPE_INTERFACE);
268 }
269 else if (invPath.find("fan") != string::npos)
270 {
271 js.emplace("type", FAN_INTERFACE);
272 }
273
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530274 for (const auto& ex : itemEEPROM["extraInterfaces"].items())
275 {
276 if (!(ex.value().is_null()))
277 {
Priyanga Ramasamydacaa472021-10-07 12:22:41 -0500278 // TODO: Remove this if condition check once inventory json is
279 // updated with xyz location code interface.
280 if (ex.key() == "com.ibm.ipzvpd.Location")
281 {
282 getExtraInterfaceProperties(
283 invPath,
284 "xyz.openbmc_project.Inventory.Decorator.LocationCode",
285 ex.value(), js);
286 }
287 else
288 {
289 getExtraInterfaceProperties(invPath, ex.key(), ex.value(),
290 js);
291 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530292 }
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500293 if ((ex.key().find("Item") != string::npos) &&
294 (ex.value().is_null()))
295 {
296 js.emplace("type", ex.key());
297 }
298 subOutput.insert(js.begin(), js.end());
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530299 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530300 }
Priyanga Ramasamy0086dd12021-09-28 10:31:50 -0500301 return subOutput;
302}
303
304json VpdTool::getPresentPropJson(const std::string& invPath,
305 std::string& parentPresence)
306{
307 std::variant<bool> response;
308 makeDBusCall(invPath, "xyz.openbmc_project.Inventory.Item", "Present")
309 .read(response);
310
311 std::string presence{};
312
313 if (auto pVal = get_if<bool>(&response))
314 {
315 presence = *pVal ? "true" : "false";
316 if (parentPresence.empty())
317 {
318 parentPresence = presence;
319 }
320 }
321 else
322 {
323 presence = parentPresence;
324 }
325
326 json js;
327 js.emplace("Present", presence);
328 return js;
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530329}
330
331json VpdTool::parseInvJson(const json& jsObject, char flag, string fruPath)
332{
333 json output = json::object({});
334 bool validObject = false;
335
336 if (jsObject.find("frus") == jsObject.end())
337 {
338 throw runtime_error("Frus missing in Inventory json");
339 }
340 else
341 {
342 for (const auto& itemFRUS : jsObject["frus"].items())
343 {
Priyanga Ramasamy0086dd12021-09-28 10:31:50 -0500344 string parentPresence{};
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530345 for (auto itemEEPROM : itemFRUS.value())
346 {
Priyanga Ramasamy0086dd12021-09-28 10:31:50 -0500347 json subOutput = json::object({});
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530348 try
349 {
350 if (flag == 'O')
351 {
352 if (itemEEPROM.find("inventoryPath") ==
353 itemEEPROM.end())
354 {
355 throw runtime_error("Inventory Path not found");
356 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530357 else if (itemEEPROM.at("inventoryPath") == fruPath)
358 {
359 validObject = true;
Priyanga Ramasamy0086dd12021-09-28 10:31:50 -0500360 subOutput = interfaceDecider(itemEEPROM);
361 json presentJs = getPresentPropJson(
362 "/xyz/openbmc_project/inventory" + fruPath,
363 parentPresence);
364 subOutput.insert(presentJs.begin(),
365 presentJs.end());
366 output.emplace(fruPath, subOutput);
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530367 return output;
368 }
Priyanga Ramasamy0086dd12021-09-28 10:31:50 -0500369 else // this else is to keep track of parent present
370 // property.
371 {
372 json presentJs = getPresentPropJson(
373 "/xyz/openbmc_project/inventory" +
374 string(itemEEPROM.at("inventoryPath")),
375 parentPresence);
376 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530377 }
378 else
379 {
Priyanga Ramasamy0086dd12021-09-28 10:31:50 -0500380 subOutput = interfaceDecider(itemEEPROM);
381 json presentJs = getPresentPropJson(
382 "/xyz/openbmc_project/inventory" +
383 string(itemEEPROM.at("inventoryPath")),
384 parentPresence);
385 subOutput.insert(presentJs.begin(), presentJs.end());
386 output.emplace(string(itemEEPROM.at("inventoryPath")),
387 subOutput);
388 }
389 }
390 catch (const sdbusplus::exception::SdBusError& e)
391 {
392 // if any of frupath doesn't have Present property of its
393 // own, emplace its parent's present property value.
394 if (e.name() == std::string("org.freedesktop.DBus.Error."
395 "UnknownProperty") &&
396 (((flag == 'O') && validObject) || flag == 'I'))
397 {
398 json presentJs;
399 presentJs.emplace("Present", parentPresence);
400 subOutput.insert(presentJs.begin(), presentJs.end());
401 output.emplace(string(itemEEPROM.at("inventoryPath")),
402 subOutput);
403 }
404
405 // for the user given child frupath which doesn't have
406 // Present prop (vpd-tool -o).
407 if ((flag == 'O') && validObject)
408 {
409 return output;
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530410 }
411 }
Patrick Williams8e15b932021-10-06 13:04:22 -0500412 catch (const exception& e)
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530413 {
414 cerr << e.what();
415 }
416 }
417 }
418 if ((flag == 'O') && (!validObject))
419 {
420 throw runtime_error(
421 "Invalid object path. Refer --dumpInventory/-i option.");
422 }
423 }
424 return output;
425}
426
427void VpdTool::dumpInventory(const nlohmann::basic_json<>& jsObject)
428{
429 char flag = 'I';
PriyangaRamasamycdf943c2020-03-18 02:25:30 +0530430 json output = json::array({});
431 output.emplace_back(parseInvJson(jsObject, flag, ""));
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530432 debugger(output);
433}
434
435void VpdTool::dumpObject(const nlohmann::basic_json<>& jsObject)
436{
437 char flag = 'O';
PriyangaRamasamycdf943c2020-03-18 02:25:30 +0530438 json output = json::array({});
Santosh Puranikd5d52bb2020-07-28 15:08:10 +0530439 output.emplace_back(parseInvJson(jsObject, flag, fruPath));
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530440 debugger(output);
441}
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530442
443void VpdTool::readKeyword()
444{
445 string interface = "com.ibm.ipzvpd.";
446 variant<Binary> response;
447
448 try
449 {
450 json output = json::object({});
451 json kwVal = json::object({});
452 makeDBusCall(INVENTORY_PATH + fruPath, interface + recordName, keyword)
453 .read(response);
454
PriyangaRamasamy887a42a2020-09-03 00:33:57 +0530455 string printableVal{};
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530456 if (auto vec = get_if<Binary>(&response))
457 {
PriyangaRamasamy887a42a2020-09-03 00:33:57 +0530458 printableVal = getPrintableValue(*vec);
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530459 }
PriyangaRamasamy887a42a2020-09-03 00:33:57 +0530460 kwVal.emplace(keyword, printableVal);
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530461
462 output.emplace(fruPath, kwVal);
463
464 debugger(output);
465 }
Patrick Williams8e15b932021-10-06 13:04:22 -0500466 catch (const json::exception& e)
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530467 {
468 json output = json::object({});
469 json kwVal = json::object({});
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530470 }
471}
PriyangaRamasamyd09d2ec2020-03-12 14:11:50 +0530472
473int VpdTool::updateKeyword()
474{
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +0530475 Binary val = toBinary(value);
PriyangaRamasamyd09d2ec2020-03-12 14:11:50 +0530476 auto bus = sdbusplus::bus::new_default();
477 auto properties =
478 bus.new_method_call(BUSNAME, OBJPATH, IFACE, "WriteKeyword");
479 properties.append(static_cast<sdbusplus::message::object_path>(fruPath));
480 properties.append(recordName);
481 properties.append(keyword);
482 properties.append(val);
483 auto result = bus.call(properties);
484
485 if (result.is_method_error())
486 {
487 throw runtime_error("Get api failed");
488 }
489 return 0;
490}
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530491
492void VpdTool::forceReset(const nlohmann::basic_json<>& jsObject)
493{
494 for (const auto& itemFRUS : jsObject["frus"].items())
495 {
496 for (const auto& itemEEPROM : itemFRUS.value().items())
497 {
498 string fru = itemEEPROM.value().at("inventoryPath");
499
500 fs::path fruCachePath = INVENTORY_MANAGER_CACHE;
501 fruCachePath += INVENTORY_PATH;
502 fruCachePath += fru;
503
504 try
505 {
506 for (const auto& it : fs::directory_iterator(fruCachePath))
507 {
508 if (fs::is_regular_file(it.status()))
509 {
510 fs::remove(it);
511 }
512 }
513 }
514 catch (const fs::filesystem_error& e)
515 {
516 }
517 }
518 }
519
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600520 cout.flush();
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530521 string udevRemove = "udevadm trigger -c remove -s \"*nvmem*\" -v";
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600522 int returnCode = system(udevRemove.c_str());
523 printReturnCode(returnCode);
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530524
525 string invManagerRestart =
526 "systemctl restart xyz.openbmc_project.Inventory.Manager.service";
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600527 returnCode = system(invManagerRestart.c_str());
528 printReturnCode(returnCode);
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530529
Santosh Puranik6c7a84e2022-03-09 13:42:18 +0530530 string sysVpdRestart = "systemctl restart system-vpd.service";
531 returnCode = system(sysVpdRestart.c_str());
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600532 printReturnCode(returnCode);
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530533
534 string udevAdd = "udevadm trigger -c add -s \"*nvmem*\" -v";
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600535 returnCode = system(udevAdd.c_str());
536 printReturnCode(returnCode);
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530537}
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +0530538
Priyanga Ramasamyc99a0b02022-06-08 14:53:39 -0500539int VpdTool::updateHardware(const uint32_t offset)
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +0530540{
541 int rc = 0;
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +0530542 const Binary& val = static_cast<const Binary&>(toBinary(value));
543 ifstream inventoryJson(INVENTORY_JSON_SYM_LINK);
544 try
545 {
546 auto json = nlohmann::json::parse(inventoryJson);
547 EditorImpl edit(fruPath, json, recordName, keyword);
Priyanga Ramasamyc99a0b02022-06-08 14:53:39 -0500548
549 edit.updateKeyword(val, offset, false);
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +0530550 }
Patrick Williams8e15b932021-10-06 13:04:22 -0500551 catch (const json::parse_error& ex)
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +0530552 {
553 throw(VpdJsonException("Json Parsing failed", INVENTORY_JSON_SYM_LINK));
554 }
555 return rc;
Priyanga Ramasamy38031312021-10-07 16:39:13 -0500556}
557
Priyanga Ramasamyc99a0b02022-06-08 14:53:39 -0500558void VpdTool::readKwFromHw(const uint32_t& startOffset)
Priyanga Ramasamy38031312021-10-07 16:39:13 -0500559{
Priyanga Ramasamy38031312021-10-07 16:39:13 -0500560 ifstream inventoryJson(INVENTORY_JSON_SYM_LINK);
561 auto jsonFile = nlohmann::json::parse(inventoryJson);
562
Priyanga Ramasamy38031312021-10-07 16:39:13 -0500563 Binary completeVPDFile;
564 completeVPDFile.resize(65504);
565 fstream vpdFileStream;
566 vpdFileStream.open(fruPath,
567 std::ios::in | std::ios::out | std::ios::binary);
568
569 vpdFileStream.seekg(startOffset, ios_base::cur);
570 vpdFileStream.read(reinterpret_cast<char*>(&completeVPDFile[0]), 65504);
571 completeVPDFile.resize(vpdFileStream.gcount());
572 vpdFileStream.clear(std::ios_base::eofbit);
573
574 if (completeVPDFile.empty())
575 {
576 throw std::runtime_error("Invalid File");
577 }
Sunny Srivastavaf31a91b2022-06-09 08:11:29 -0500578
579 const std::string& inventoryPath =
580 jsonFile["frus"][fruPath][0]["inventoryPath"];
581
582 Impl obj(completeVPDFile, (constants::pimPath + inventoryPath));
Priyanga Ramasamy38031312021-10-07 16:39:13 -0500583 std::string keywordVal = obj.readKwFromHw(recordName, keyword);
584
585 if (!keywordVal.empty())
586 {
587 json output = json::object({});
588 json kwVal = json::object({});
589 kwVal.emplace(keyword, keywordVal);
590
591 output.emplace(fruPath, kwVal);
592
593 debugger(output);
594 }
595 else
596 {
597 std::cerr << "The given keyword " << keyword << " or record "
598 << recordName
599 << " or both are not present in the given FRU path "
600 << fruPath << std::endl;
601 }
602}
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500603
604void VpdTool::printFixSystemVPDOption(UserOption option)
605{
606 switch (option)
607 {
608 case VpdTool::EXIT:
609 cout << "\nEnter 0 => To exit successfully : ";
610 break;
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600611 case VpdTool::BACKUP_DATA_FOR_ALL:
612 cout << "\n\nEnter 1 => If you choose the data on backup for all "
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500613 "mismatching record-keyword pairs";
614 break;
615 case VpdTool::SYSTEM_BACKPLANE_DATA_FOR_ALL:
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600616 cout << "\nEnter 2 => If you choose the data on primary for all "
617 "mismatching record-keyword pairs";
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500618 break;
619 case VpdTool::MORE_OPTIONS:
620 cout << "\nEnter 3 => If you wish to explore more options";
621 break;
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600622 case VpdTool::BACKUP_DATA_FOR_CURRENT:
623 cout << "\nEnter 4 => If you choose the data on backup as the "
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500624 "right value";
625 break;
626 case VpdTool::SYSTEM_BACKPLANE_DATA_FOR_CURRENT:
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600627 cout << "\nEnter 5 => If you choose the data on primary as the "
628 "right value";
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500629 break;
630 case VpdTool::NEW_VALUE_ON_BOTH:
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600631 cout << "\nEnter 6 => If you wish to enter a new value to update "
632 "both on backup and primary";
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500633 break;
634 case VpdTool::SKIP_CURRENT:
635 cout << "\nEnter 7 => If you wish to skip the above "
636 "record-keyword pair";
637 break;
638 }
639}
640
Priyanga Ramasamy6d5e7342022-10-14 07:17:25 -0500641void VpdTool::getSystemDataFromCache(IntfPropMap& svpdBusData)
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500642{
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500643 const auto vsys = getAllDBusProperty<GetAllResultType>(
644 constants::pimIntf,
645 "/xyz/openbmc_project/inventory/system/chassis/motherboard",
646 "com.ibm.ipzvpd.VSYS");
647 svpdBusData.emplace("VSYS", vsys);
648
649 const auto vcen = getAllDBusProperty<GetAllResultType>(
650 constants::pimIntf,
651 "/xyz/openbmc_project/inventory/system/chassis/motherboard",
652 "com.ibm.ipzvpd.VCEN");
653 svpdBusData.emplace("VCEN", vcen);
654
655 const auto lxr0 = getAllDBusProperty<GetAllResultType>(
656 constants::pimIntf,
657 "/xyz/openbmc_project/inventory/system/chassis/motherboard",
658 "com.ibm.ipzvpd.LXR0");
659 svpdBusData.emplace("LXR0", lxr0);
660
661 const auto util = getAllDBusProperty<GetAllResultType>(
662 constants::pimIntf,
663 "/xyz/openbmc_project/inventory/system/chassis/motherboard",
664 "com.ibm.ipzvpd.UTIL");
665 svpdBusData.emplace("UTIL", util);
Priyanga Ramasamy6d5e7342022-10-14 07:17:25 -0500666}
667
668int VpdTool::fixSystemVPD()
669{
670 std::string outline(191, '=');
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600671 cout << "\nRestorable record-keyword pairs and their data on backup & "
672 "primary.\n\n"
Priyanga Ramasamy6d5e7342022-10-14 07:17:25 -0500673 << outline << std::endl;
674
675 cout << left << setw(6) << "S.No" << left << setw(8) << "Record" << left
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600676 << setw(9) << "Keyword" << left << setw(75) << "Data On Backup" << left
677 << setw(75) << "Data On Primary" << left << setw(14)
Priyanga Ramasamy6d5e7342022-10-14 07:17:25 -0500678 << "Data Mismatch\n"
679 << outline << std::endl;
680
681 int num = 0;
682
683 // Get system VPD data in map
684 unordered_map<string, DbusPropertyMap> vpdMap;
685 json js;
686 getVPDInMap(constants::systemVpdFilePath, vpdMap, js,
687 constants::pimPath +
688 static_cast<std::string>(constants::SYSTEM_OBJECT));
689
690 // Get system VPD D-Bus Data in a map
691 IntfPropMap svpdBusData;
692 getSystemDataFromCache(svpdBusData);
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500693
694 for (const auto& recordKw : svpdKwdMap)
695 {
696 string record = recordKw.first;
697
698 // Extract specific record data from the svpdBusData map.
699 const auto& rec = svpdBusData.find(record);
700
701 if (rec == svpdBusData.end())
702 {
703 std::cerr << record << " not a part of critical system VPD records."
704 << std::endl;
705 continue;
706 }
707
708 const auto& recData = svpdBusData.find(record)->second;
709
710 string busStr{}, hwValStr{};
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500711
Priyanga Ramasamy952d6c52022-11-07 07:20:24 -0600712 for (const auto& keywordInfo : recordKw.second)
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500713 {
Priyanga Ramasamy952d6c52022-11-07 07:20:24 -0600714 const auto& keyword = get<0>(keywordInfo);
Priyanga Ramasamy6d5e7342022-10-14 07:17:25 -0500715 string mismatch = "NO"; // no mismatch
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500716 string hardwareValue{};
717 auto recItr = vpdMap.find(record);
718
719 if (recItr != vpdMap.end())
720 {
721 DbusPropertyMap& kwValMap = recItr->second;
722 auto kwItr = kwValMap.find(keyword);
723 if (kwItr != kwValMap.end())
724 {
725 hardwareValue = kwItr->second;
726 }
727 }
728
Priyanga Ramasamy6d5e7342022-10-14 07:17:25 -0500729 inventory::Value kwValue;
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500730 for (auto& kwData : recData)
731 {
732 if (kwData.first == keyword)
733 {
734 kwValue = kwData.second;
735 break;
736 }
737 }
738
739 if (keyword != "SE")
740 {
741 ostringstream hwValStream;
742 hwValStream << "0x";
743 hwValStr = hwValStream.str();
744
745 for (uint16_t byte : hardwareValue)
746 {
747 hwValStream << setfill('0') << setw(2) << hex << byte;
748 hwValStr = hwValStream.str();
749 }
750
751 if (const auto value = get_if<Binary>(&kwValue))
752 {
753 busStr = byteArrayToHexString(*value);
754 }
755 if (busStr != hwValStr)
756 {
757 mismatch = "YES";
758 }
759 }
760 else
761 {
762 if (const auto value = get_if<Binary>(&kwValue))
763 {
764 busStr = getPrintableValue(*value);
765 }
766 if (busStr != hardwareValue)
767 {
768 mismatch = "YES";
769 }
770 hwValStr = hardwareValue;
771 }
772 recKwData.push_back(
773 make_tuple(++num, record, keyword, busStr, hwValStr, mismatch));
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500774
Priyanga Ramasamy0ac10852022-10-26 05:35:42 -0500775 std::string splitLine(191, '-');
776 cout << left << setw(6) << num << left << setw(8) << record << left
777 << setw(9) << keyword << left << setw(75) << setfill(' ')
778 << busStr << left << setw(75) << setfill(' ') << hwValStr
779 << left << setw(14) << mismatch << '\n'
780 << splitLine << endl;
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500781 }
782 }
783 parseSVPDOptions(js);
784 return 0;
785}
786
787void VpdTool::parseSVPDOptions(const nlohmann::json& json)
788{
789 do
790 {
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600791 printFixSystemVPDOption(VpdTool::BACKUP_DATA_FOR_ALL);
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500792 printFixSystemVPDOption(VpdTool::SYSTEM_BACKPLANE_DATA_FOR_ALL);
793 printFixSystemVPDOption(VpdTool::MORE_OPTIONS);
794 printFixSystemVPDOption(VpdTool::EXIT);
795
796 int option = 0;
797 cin >> option;
Priyanga Ramasamy0ac10852022-10-26 05:35:42 -0500798
799 std::string outline(191, '=');
800 cout << '\n' << outline << endl;
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500801
802 if (json.find("frus") == json.end())
803 {
804 throw runtime_error("Frus not found in json");
805 }
806
807 bool mismatchFound = false;
808
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600809 if (option == VpdTool::BACKUP_DATA_FOR_ALL)
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500810 {
811 for (const auto& data : recKwData)
812 {
813 if (get<5>(data) == "YES")
814 {
815 EditorImpl edit(constants::systemVpdFilePath, json,
816 get<1>(data), get<2>(data));
817 edit.updateKeyword(toBinary(get<3>(data)), 0, true);
818 mismatchFound = true;
819 }
820 }
821
822 if (mismatchFound)
823 {
824 cout << "\nData updated successfully for all mismatching "
825 "record-keyword pairs by choosing their corresponding "
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600826 "data from backup. Exit successfully.\n"
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500827 << endl;
828 }
829 else
830 {
831 cout << "\nNo mismatch found for any of the above mentioned "
832 "record-keyword pair. Exit successfully.\n";
833 }
834
835 exit(0);
836 }
837 else if (option == VpdTool::SYSTEM_BACKPLANE_DATA_FOR_ALL)
838 {
839 for (const auto& data : recKwData)
840 {
841 if (get<5>(data) == "YES")
842 {
843 EditorImpl edit(constants::systemVpdFilePath, json,
844 get<1>(data), get<2>(data));
845 edit.updateKeyword(toBinary(get<4>(data)), 0, true);
846 mismatchFound = true;
847 }
848 }
849
850 if (mismatchFound)
851 {
852 cout << "\nData updated successfully for all mismatching "
853 "record-keyword pairs by choosing their corresponding "
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600854 "data from primary VPD.\n"
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500855 << endl;
856 }
857 else
858 {
859 cout << "\nNo mismatch found for any of the above mentioned "
860 "record-keyword pair. Exit successfully.\n";
861 }
862
863 exit(0);
864 }
865 else if (option == VpdTool::MORE_OPTIONS)
866 {
867 cout << "\nIterate through all restorable record-keyword pairs\n";
868
869 for (const auto& data : recKwData)
870 {
871 do
872 {
Priyanga Ramasamy0ac10852022-10-26 05:35:42 -0500873 cout << '\n' << outline << endl;
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500874
875 cout << left << setw(6) << "S.No" << left << setw(8)
876 << "Record" << left << setw(9) << "Keyword" << left
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600877 << setw(75) << setfill(' ') << "Backup Data" << left
878 << setw(75) << setfill(' ') << "Primary Data" << left
879 << setw(14) << "Data Mismatch" << endl;
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500880
881 cout << left << setw(6) << get<0>(data) << left << setw(8)
882 << get<1>(data) << left << setw(9) << get<2>(data)
Priyanga Ramasamy0ac10852022-10-26 05:35:42 -0500883 << left << setw(75) << setfill(' ') << get<3>(data)
884 << left << setw(75) << setfill(' ') << get<4>(data)
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500885 << left << setw(14) << get<5>(data);
886
Priyanga Ramasamy0ac10852022-10-26 05:35:42 -0500887 cout << '\n' << outline << endl;
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500888
889 if (get<5>(data) == "NO")
890 {
891 cout << "\nNo mismatch found.\n";
892 printFixSystemVPDOption(VpdTool::NEW_VALUE_ON_BOTH);
893 printFixSystemVPDOption(VpdTool::SKIP_CURRENT);
894 printFixSystemVPDOption(VpdTool::EXIT);
895 }
896 else
897 {
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600898 printFixSystemVPDOption(
899 VpdTool::BACKUP_DATA_FOR_CURRENT);
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500900 printFixSystemVPDOption(
901 VpdTool::SYSTEM_BACKPLANE_DATA_FOR_CURRENT);
902 printFixSystemVPDOption(VpdTool::NEW_VALUE_ON_BOTH);
903 printFixSystemVPDOption(VpdTool::SKIP_CURRENT);
904 printFixSystemVPDOption(VpdTool::EXIT);
905 }
906
907 cin >> option;
Priyanga Ramasamy0ac10852022-10-26 05:35:42 -0500908 cout << '\n' << outline << endl;
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500909
910 EditorImpl edit(constants::systemVpdFilePath, json,
911 get<1>(data), get<2>(data));
912
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600913 if (option == VpdTool::BACKUP_DATA_FOR_CURRENT)
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500914 {
915 edit.updateKeyword(toBinary(get<3>(data)), 0, true);
916 cout << "\nData updated successfully.\n";
917 break;
918 }
919 else if (option ==
920 VpdTool::SYSTEM_BACKPLANE_DATA_FOR_CURRENT)
921 {
922 edit.updateKeyword(toBinary(get<4>(data)), 0, true);
923 cout << "\nData updated successfully.\n";
924 break;
925 }
926 else if (option == VpdTool::NEW_VALUE_ON_BOTH)
927 {
928 string value;
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600929 cout << "\nEnter the new value to update on both "
930 "primary & backup. Value should be in ASCII or "
931 "in HEX(prefixed with 0x) : ";
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500932 cin >> value;
Priyanga Ramasamy0ac10852022-10-26 05:35:42 -0500933 cout << '\n' << outline << endl;
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500934
935 edit.updateKeyword(toBinary(value), 0, true);
936 cout << "\nData updated successfully.\n";
937 break;
938 }
939 else if (option == VpdTool::SKIP_CURRENT)
940 {
941 cout << "\nSkipped the above record-keyword pair. "
942 "Continue to the next available pair.\n";
943 break;
944 }
945 else if (option == VpdTool::EXIT)
946 {
947 cout << "\nExit successfully\n";
948 exit(0);
949 }
950 else
951 {
952 cout << "\nProvide a valid option. Retrying for the "
953 "current record-keyword pair\n";
954 }
955 } while (1);
956 }
957 exit(0);
958 }
959 else if (option == VpdTool::EXIT)
960 {
961 cout << "\nExit successfully";
962 exit(0);
963 }
964 else
965 {
966 cout << "\nProvide a valid option. Retry.";
967 continue;
968 }
969
970 } while (true);
Priyanga Ramasamy124ae6c2022-10-18 12:46:14 -0500971}
972
973int VpdTool::cleanSystemVPD()
974{
975 try
976 {
977 // Get system VPD hardware data in map
978 unordered_map<string, DbusPropertyMap> vpdMap;
979 json js;
980 getVPDInMap(constants::systemVpdFilePath, vpdMap, js,
981 constants::pimPath +
982 static_cast<std::string>(constants::SYSTEM_OBJECT));
983
984 RecKwValMap kwdsToBeUpdated;
985
986 for (auto recordMap : svpdKwdMap)
987 {
988 const auto& record = recordMap.first;
989 std::unordered_map<std::string, Binary> kwDefault;
990 for (auto keywordMap : recordMap.second)
991 {
992 // Skip those keywords which cannot be reset at manufacturing
993 if (!std::get<3>(keywordMap))
994 {
995 continue;
996 }
997 const auto& keyword = std::get<0>(keywordMap);
998
999 // Get hardware value for this keyword from vpdMap
1000 Binary hardwareValue;
1001
1002 auto recItr = vpdMap.find(record);
1003
1004 if (recItr != vpdMap.end())
1005 {
1006 DbusPropertyMap& kwValMap = recItr->second;
1007 auto kwItr = kwValMap.find(keyword);
1008 if (kwItr != kwValMap.end())
1009 {
1010 hardwareValue = toBinary(kwItr->second);
1011 }
1012 }
1013
1014 // compare hardware value with the keyword's default value
1015 auto defaultValue = std::get<1>(keywordMap);
1016 if (hardwareValue != defaultValue)
1017 {
1018 EditorImpl edit(constants::systemVpdFilePath, js, record,
1019 keyword);
1020 edit.updateKeyword(defaultValue, 0, true);
1021 }
1022 }
1023 }
1024
1025 std::cout
1026 << "\n The critical keywords from system backplane VPD has been "
1027 "reset successfully."
1028 << std::endl;
1029 }
1030 catch (const std::exception& e)
1031 {
1032 std::cerr << e.what();
1033 std::cerr
1034 << "\nManufacturing reset on system vpd keywords is unsuccessful";
1035 }
1036 return 0;
Priyanga Ramasamy952d6c52022-11-07 07:20:24 -06001037}