blob: 10eba2e020678dd31dd853cab24ab068e83f40b5 [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
25Binary VpdTool::toBinary(const std::string& value)
26{
27 Binary val{};
28 if (value.find("0x") == string::npos)
29 {
30 val.assign(value.begin(), value.end());
31 }
32 else if (value.find("0x") != string::npos)
33 {
34 stringstream ss;
35 ss.str(value.substr(2));
36 string byteStr{};
37
Priyanga Ramasamyec912e62021-12-15 22:47:51 -060038 if (value.length() % 2 != 0)
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +053039 {
Priyanga Ramasamyec912e62021-12-15 22:47:51 -060040 throw runtime_error(
41 "VPD-TOOL write option accepts 2 digit hex numbers. (Eg. 0x1 "
42 "should be given as 0x01). Aborting the write operation.");
43 }
44
45 if (value.find_first_not_of("0123456789abcdefABCDEF", 2) !=
46 std::string::npos)
47 {
48 throw runtime_error("Provide a valid hexadecimal input.");
49 }
50
51 while (ss >> setw(2) >> byteStr)
52 {
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +053053 uint8_t byte = strtoul(byteStr.c_str(), nullptr, 16);
54
55 val.push_back(byte);
56 }
57 }
58
59 else
60 {
61 throw runtime_error("The value to be updated should be either in ascii "
62 "or in hex. Refer --help option");
63 }
64 return val;
65}
PriyangaRamasamycdf943c2020-03-18 02:25:30 +053066
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -060067void VpdTool::printReturnCode(int returnCode)
68{
69 if (returnCode)
70 {
71 cout << "\n Command failed with the return code " << returnCode
72 << ". Continuing the execution. " << endl;
73 }
74}
75
PriyangaRamasamycdf943c2020-03-18 02:25:30 +053076void VpdTool::eraseInventoryPath(string& fru)
77{
78 // Power supply frupath comes with INVENTORY_PATH appended in prefix.
79 // Stripping it off inorder to avoid INVENTORY_PATH duplication
80 // during getVINIProperties() execution.
81 fru.erase(0, sizeof(INVENTORY_PATH) - 1);
82}
83
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +053084void VpdTool::debugger(json output)
85{
86 cout << output.dump(4) << '\n';
87}
88
89auto VpdTool::makeDBusCall(const string& objectName, const string& interface,
90 const string& kw)
91{
92 auto bus = sdbusplus::bus::new_default();
93 auto properties =
94 bus.new_method_call(INVENTORY_MANAGER_SERVICE, objectName.c_str(),
95 "org.freedesktop.DBus.Properties", "Get");
96 properties.append(interface);
97 properties.append(kw);
98 auto result = bus.call(properties);
99
100 if (result.is_method_error())
101 {
102 throw runtime_error("Get api failed");
103 }
104 return result;
105}
106
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500107json VpdTool::getVINIProperties(string invPath)
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530108{
109 variant<Binary> response;
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530110 json kwVal = json::object({});
111
112 vector<string> keyword{"CC", "SN", "PN", "FN", "DR"};
113 string interface = "com.ibm.ipzvpd.VINI";
PriyangaRamasamycdf943c2020-03-18 02:25:30 +0530114 string objectName = {};
115
116 if (invPath.find(INVENTORY_PATH) != string::npos)
117 {
118 objectName = invPath;
119 eraseInventoryPath(invPath);
120 }
121 else
122 {
123 objectName = INVENTORY_PATH + invPath;
124 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530125 for (string kw : keyword)
126 {
127 try
128 {
129 makeDBusCall(objectName, interface, kw).read(response);
130
131 if (auto vec = get_if<Binary>(&response))
132 {
PriyangaRamasamy887a42a2020-09-03 00:33:57 +0530133 string printableVal = getPrintableValue(*vec);
134 kwVal.emplace(kw, printableVal);
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530135 }
136 }
Patrick Williams2eb01762022-07-22 19:26:56 -0500137 catch (const sdbusplus::exception_t& e)
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530138 {
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500139 if (string(e.name()) ==
140 string("org.freedesktop.DBus.Error.UnknownObject"))
141 {
142 kwVal.emplace(invPath, json::object({}));
143 objFound = false;
144 break;
145 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530146 }
147 }
148
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500149 return kwVal;
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530150}
151
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500152void VpdTool::getExtraInterfaceProperties(const string& invPath,
153 const string& extraInterface,
154 const json& prop, json& output)
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530155{
156 variant<string> response;
157
158 string objectName = INVENTORY_PATH + invPath;
159
160 for (const auto& itProp : prop.items())
161 {
162 string kw = itProp.key();
163 try
164 {
165 makeDBusCall(objectName, extraInterface, kw).read(response);
166
167 if (auto str = get_if<string>(&response))
168 {
169 output.emplace(kw, *str);
170 }
171 }
Patrick Williams2eb01762022-07-22 19:26:56 -0500172 catch (const sdbusplus::exception_t& e)
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530173 {
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500174 if (std::string(e.name()) ==
175 std::string("org.freedesktop.DBus.Error.UnknownObject"))
176 {
177 objFound = false;
178 break;
179 }
180 else if (std::string(e.name()) ==
181 std::string("org.freedesktop.DBus.Error.UnknownProperty"))
182 {
183 output.emplace(kw, "");
184 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530185 }
186 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530187}
188
189json VpdTool::interfaceDecider(json& itemEEPROM)
190{
191 if (itemEEPROM.find("inventoryPath") == itemEEPROM.end())
192 {
193 throw runtime_error("Inventory Path not found");
194 }
195
196 if (itemEEPROM.find("extraInterfaces") == itemEEPROM.end())
197 {
198 throw runtime_error("Extra Interfaces not found");
199 }
200
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500201 json subOutput = json::object({});
Alpana Kumarib6965f12020-06-01 00:32:21 -0500202 fruType = "FRU";
203
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500204 json j;
205 objFound = true;
206 string invPath = itemEEPROM.at("inventoryPath");
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530207
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500208 j = getVINIProperties(invPath);
209
210 if (objFound)
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530211 {
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500212 subOutput.insert(j.begin(), j.end());
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530213 json js;
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500214 if (itemEEPROM.find("type") != itemEEPROM.end())
215 {
216 fruType = itemEEPROM.at("type");
217 }
218 js.emplace("TYPE", fruType);
219
220 if (invPath.find("powersupply") != string::npos)
221 {
222 js.emplace("type", POWER_SUPPLY_TYPE_INTERFACE);
223 }
224 else if (invPath.find("fan") != string::npos)
225 {
226 js.emplace("type", FAN_INTERFACE);
227 }
228
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530229 for (const auto& ex : itemEEPROM["extraInterfaces"].items())
230 {
231 if (!(ex.value().is_null()))
232 {
Priyanga Ramasamydacaa472021-10-07 12:22:41 -0500233 // TODO: Remove this if condition check once inventory json is
234 // updated with xyz location code interface.
235 if (ex.key() == "com.ibm.ipzvpd.Location")
236 {
237 getExtraInterfaceProperties(
238 invPath,
239 "xyz.openbmc_project.Inventory.Decorator.LocationCode",
240 ex.value(), js);
241 }
242 else
243 {
244 getExtraInterfaceProperties(invPath, ex.key(), ex.value(),
245 js);
246 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530247 }
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500248 if ((ex.key().find("Item") != string::npos) &&
249 (ex.value().is_null()))
250 {
251 js.emplace("type", ex.key());
252 }
253 subOutput.insert(js.begin(), js.end());
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530254 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530255 }
Priyanga Ramasamy0086dd12021-09-28 10:31:50 -0500256 return subOutput;
257}
258
259json VpdTool::getPresentPropJson(const std::string& invPath,
260 std::string& parentPresence)
261{
262 std::variant<bool> response;
263 makeDBusCall(invPath, "xyz.openbmc_project.Inventory.Item", "Present")
264 .read(response);
265
266 std::string presence{};
267
268 if (auto pVal = get_if<bool>(&response))
269 {
270 presence = *pVal ? "true" : "false";
271 if (parentPresence.empty())
272 {
273 parentPresence = presence;
274 }
275 }
276 else
277 {
278 presence = parentPresence;
279 }
280
281 json js;
282 js.emplace("Present", presence);
283 return js;
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530284}
285
286json VpdTool::parseInvJson(const json& jsObject, char flag, string fruPath)
287{
288 json output = json::object({});
289 bool validObject = false;
290
291 if (jsObject.find("frus") == jsObject.end())
292 {
293 throw runtime_error("Frus missing in Inventory json");
294 }
295 else
296 {
297 for (const auto& itemFRUS : jsObject["frus"].items())
298 {
Priyanga Ramasamy0086dd12021-09-28 10:31:50 -0500299 string parentPresence{};
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530300 for (auto itemEEPROM : itemFRUS.value())
301 {
Priyanga Ramasamy0086dd12021-09-28 10:31:50 -0500302 json subOutput = json::object({});
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530303 try
304 {
305 if (flag == 'O')
306 {
307 if (itemEEPROM.find("inventoryPath") ==
308 itemEEPROM.end())
309 {
310 throw runtime_error("Inventory Path not found");
311 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530312 else if (itemEEPROM.at("inventoryPath") == fruPath)
313 {
314 validObject = true;
Priyanga Ramasamy0086dd12021-09-28 10:31:50 -0500315 subOutput = interfaceDecider(itemEEPROM);
316 json presentJs = getPresentPropJson(
317 "/xyz/openbmc_project/inventory" + fruPath,
318 parentPresence);
319 subOutput.insert(presentJs.begin(),
320 presentJs.end());
321 output.emplace(fruPath, subOutput);
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530322 return output;
323 }
Priyanga Ramasamy0086dd12021-09-28 10:31:50 -0500324 else // this else is to keep track of parent present
325 // property.
326 {
327 json presentJs = getPresentPropJson(
328 "/xyz/openbmc_project/inventory" +
329 string(itemEEPROM.at("inventoryPath")),
330 parentPresence);
331 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530332 }
333 else
334 {
Priyanga Ramasamy0086dd12021-09-28 10:31:50 -0500335 subOutput = interfaceDecider(itemEEPROM);
336 json presentJs = getPresentPropJson(
337 "/xyz/openbmc_project/inventory" +
338 string(itemEEPROM.at("inventoryPath")),
339 parentPresence);
340 subOutput.insert(presentJs.begin(), presentJs.end());
341 output.emplace(string(itemEEPROM.at("inventoryPath")),
342 subOutput);
343 }
344 }
345 catch (const sdbusplus::exception::SdBusError& e)
346 {
347 // if any of frupath doesn't have Present property of its
348 // own, emplace its parent's present property value.
349 if (e.name() == std::string("org.freedesktop.DBus.Error."
350 "UnknownProperty") &&
351 (((flag == 'O') && validObject) || flag == 'I'))
352 {
353 json presentJs;
354 presentJs.emplace("Present", parentPresence);
355 subOutput.insert(presentJs.begin(), presentJs.end());
356 output.emplace(string(itemEEPROM.at("inventoryPath")),
357 subOutput);
358 }
359
360 // for the user given child frupath which doesn't have
361 // Present prop (vpd-tool -o).
362 if ((flag == 'O') && validObject)
363 {
364 return output;
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530365 }
366 }
Patrick Williams8e15b932021-10-06 13:04:22 -0500367 catch (const exception& e)
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530368 {
369 cerr << e.what();
370 }
371 }
372 }
373 if ((flag == 'O') && (!validObject))
374 {
375 throw runtime_error(
376 "Invalid object path. Refer --dumpInventory/-i option.");
377 }
378 }
379 return output;
380}
381
382void VpdTool::dumpInventory(const nlohmann::basic_json<>& jsObject)
383{
384 char flag = 'I';
PriyangaRamasamycdf943c2020-03-18 02:25:30 +0530385 json output = json::array({});
386 output.emplace_back(parseInvJson(jsObject, flag, ""));
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530387 debugger(output);
388}
389
390void VpdTool::dumpObject(const nlohmann::basic_json<>& jsObject)
391{
392 char flag = 'O';
PriyangaRamasamycdf943c2020-03-18 02:25:30 +0530393 json output = json::array({});
Santosh Puranikd5d52bb2020-07-28 15:08:10 +0530394 output.emplace_back(parseInvJson(jsObject, flag, fruPath));
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530395 debugger(output);
396}
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530397
398void VpdTool::readKeyword()
399{
400 string interface = "com.ibm.ipzvpd.";
401 variant<Binary> response;
402
403 try
404 {
405 json output = json::object({});
406 json kwVal = json::object({});
407 makeDBusCall(INVENTORY_PATH + fruPath, interface + recordName, keyword)
408 .read(response);
409
PriyangaRamasamy887a42a2020-09-03 00:33:57 +0530410 string printableVal{};
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530411 if (auto vec = get_if<Binary>(&response))
412 {
PriyangaRamasamy887a42a2020-09-03 00:33:57 +0530413 printableVal = getPrintableValue(*vec);
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530414 }
PriyangaRamasamy887a42a2020-09-03 00:33:57 +0530415 kwVal.emplace(keyword, printableVal);
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530416
417 output.emplace(fruPath, kwVal);
418
419 debugger(output);
420 }
Patrick Williams8e15b932021-10-06 13:04:22 -0500421 catch (const json::exception& e)
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530422 {
423 json output = json::object({});
424 json kwVal = json::object({});
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530425 }
426}
PriyangaRamasamyd09d2ec2020-03-12 14:11:50 +0530427
428int VpdTool::updateKeyword()
429{
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +0530430 Binary val = toBinary(value);
PriyangaRamasamyd09d2ec2020-03-12 14:11:50 +0530431 auto bus = sdbusplus::bus::new_default();
432 auto properties =
433 bus.new_method_call(BUSNAME, OBJPATH, IFACE, "WriteKeyword");
434 properties.append(static_cast<sdbusplus::message::object_path>(fruPath));
435 properties.append(recordName);
436 properties.append(keyword);
437 properties.append(val);
438 auto result = bus.call(properties);
439
440 if (result.is_method_error())
441 {
442 throw runtime_error("Get api failed");
443 }
444 return 0;
445}
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530446
447void VpdTool::forceReset(const nlohmann::basic_json<>& jsObject)
448{
449 for (const auto& itemFRUS : jsObject["frus"].items())
450 {
451 for (const auto& itemEEPROM : itemFRUS.value().items())
452 {
453 string fru = itemEEPROM.value().at("inventoryPath");
454
455 fs::path fruCachePath = INVENTORY_MANAGER_CACHE;
456 fruCachePath += INVENTORY_PATH;
457 fruCachePath += fru;
458
459 try
460 {
461 for (const auto& it : fs::directory_iterator(fruCachePath))
462 {
463 if (fs::is_regular_file(it.status()))
464 {
465 fs::remove(it);
466 }
467 }
468 }
469 catch (const fs::filesystem_error& e)
470 {
471 }
472 }
473 }
474
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600475 cout.flush();
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530476 string udevRemove = "udevadm trigger -c remove -s \"*nvmem*\" -v";
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600477 int returnCode = system(udevRemove.c_str());
478 printReturnCode(returnCode);
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530479
480 string invManagerRestart =
481 "systemctl restart xyz.openbmc_project.Inventory.Manager.service";
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600482 returnCode = system(invManagerRestart.c_str());
483 printReturnCode(returnCode);
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530484
Santosh Puranik6c7a84e2022-03-09 13:42:18 +0530485 string sysVpdRestart = "systemctl restart system-vpd.service";
486 returnCode = system(sysVpdRestart.c_str());
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600487 printReturnCode(returnCode);
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530488
489 string udevAdd = "udevadm trigger -c add -s \"*nvmem*\" -v";
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600490 returnCode = system(udevAdd.c_str());
491 printReturnCode(returnCode);
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530492}
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +0530493
Priyanga Ramasamyc99a0b02022-06-08 14:53:39 -0500494int VpdTool::updateHardware(const uint32_t offset)
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +0530495{
496 int rc = 0;
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +0530497 const Binary& val = static_cast<const Binary&>(toBinary(value));
498 ifstream inventoryJson(INVENTORY_JSON_SYM_LINK);
499 try
500 {
501 auto json = nlohmann::json::parse(inventoryJson);
502 EditorImpl edit(fruPath, json, recordName, keyword);
Priyanga Ramasamyc99a0b02022-06-08 14:53:39 -0500503
504 edit.updateKeyword(val, offset, false);
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +0530505 }
Patrick Williams8e15b932021-10-06 13:04:22 -0500506 catch (const json::parse_error& ex)
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +0530507 {
508 throw(VpdJsonException("Json Parsing failed", INVENTORY_JSON_SYM_LINK));
509 }
510 return rc;
Priyanga Ramasamy38031312021-10-07 16:39:13 -0500511}
512
Priyanga Ramasamyc99a0b02022-06-08 14:53:39 -0500513void VpdTool::readKwFromHw(const uint32_t& startOffset)
Priyanga Ramasamy38031312021-10-07 16:39:13 -0500514{
Priyanga Ramasamy38031312021-10-07 16:39:13 -0500515 ifstream inventoryJson(INVENTORY_JSON_SYM_LINK);
516 auto jsonFile = nlohmann::json::parse(inventoryJson);
517
Priyanga Ramasamy38031312021-10-07 16:39:13 -0500518 Binary completeVPDFile;
519 completeVPDFile.resize(65504);
520 fstream vpdFileStream;
521 vpdFileStream.open(fruPath,
522 std::ios::in | std::ios::out | std::ios::binary);
523
524 vpdFileStream.seekg(startOffset, ios_base::cur);
525 vpdFileStream.read(reinterpret_cast<char*>(&completeVPDFile[0]), 65504);
526 completeVPDFile.resize(vpdFileStream.gcount());
527 vpdFileStream.clear(std::ios_base::eofbit);
528
529 if (completeVPDFile.empty())
530 {
531 throw std::runtime_error("Invalid File");
532 }
533 Impl obj(completeVPDFile);
534 std::string keywordVal = obj.readKwFromHw(recordName, keyword);
535
536 if (!keywordVal.empty())
537 {
538 json output = json::object({});
539 json kwVal = json::object({});
540 kwVal.emplace(keyword, keywordVal);
541
542 output.emplace(fruPath, kwVal);
543
544 debugger(output);
545 }
546 else
547 {
548 std::cerr << "The given keyword " << keyword << " or record "
549 << recordName
550 << " or both are not present in the given FRU path "
551 << fruPath << std::endl;
552 }
553}
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500554
555void VpdTool::printFixSystemVPDOption(UserOption option)
556{
557 switch (option)
558 {
559 case VpdTool::EXIT:
560 cout << "\nEnter 0 => To exit successfully : ";
561 break;
562 case VpdTool::BMC_DATA_FOR_ALL:
563 cout << "\n\nEnter 1 => If you choose the data on BMC for all "
564 "mismatching record-keyword pairs";
565 break;
566 case VpdTool::SYSTEM_BACKPLANE_DATA_FOR_ALL:
567 cout << "\nEnter 2 => If you choose the data on System "
568 "Backplane for all mismatching record-keyword pairs";
569 break;
570 case VpdTool::MORE_OPTIONS:
571 cout << "\nEnter 3 => If you wish to explore more options";
572 break;
573 case VpdTool::BMC_DATA_FOR_CURRENT:
574 cout << "\nEnter 4 => If you choose the data on BMC as the "
575 "right value";
576 break;
577 case VpdTool::SYSTEM_BACKPLANE_DATA_FOR_CURRENT:
578 cout << "\nEnter 5 => If you choose the data on System "
579 "Backplane as the right value";
580 break;
581 case VpdTool::NEW_VALUE_ON_BOTH:
582 cout << "\nEnter 6 => If you wish to enter a new value to "
583 "update both on BMC and System Backplane";
584 break;
585 case VpdTool::SKIP_CURRENT:
586 cout << "\nEnter 7 => If you wish to skip the above "
587 "record-keyword pair";
588 break;
589 }
590}
591
592int VpdTool::fixSystemVPD()
593{
594 cout << "\nRestorable record-keyword pairs and their data on BMC & "
595 "System Backplane.\n ";
596
597 cout << "\n|==============================================================="
598 "=======================================|"
599 << endl;
600
601 cout << left << setw(6) << "S.No" << left << setw(8) << "Record" << left
602 << setw(9) << "Keyword" << left << setw(30) << "Data On BMC" << left
603 << setw(30) << "Data On System Backplane" << left << setw(14)
604 << "Data Mismatch";
605
606 cout << "\n|==============================================================="
607 "=======================================|"
608 << endl;
609
610 int num = 0;
611
612 // Get system VPD data in map
613 Binary vpdVector{};
614 json js{};
615
616 auto jsonToParse = INVENTORY_JSON_DEFAULT;
617 if (fs::exists(INVENTORY_JSON_SYM_LINK))
618 {
619 jsonToParse = INVENTORY_JSON_SYM_LINK;
620 }
621
622 ifstream inventoryJson(jsonToParse);
623 if (!inventoryJson)
624 {
625 throw runtime_error("VPD JSON file not found");
626 }
627 js = json::parse(inventoryJson);
628
629 vpdVector = getVpdDataInVector(js, constants::systemVpdFilePath);
630 ParserInterface* parser = ParserFactory::getParser(vpdVector);
631 auto parseResult = parser->parse();
632 ParserFactory::freeParser(parser);
633
634 unordered_map<string, DbusPropertyMap> vpdMap;
635
636 if (auto pVal = get_if<Store>(&parseResult))
637 {
638 vpdMap = pVal->getVpdMap();
639 }
640 else
641 {
642 std::cerr << "\n System backplane VPD is not of type IPZ. Unable to "
643 "parse the VPD "
644 << constants::systemVpdFilePath << " . Exit with error."
645 << std::endl;
646 exit(1);
647 }
648
649 // Get system VPD D-Bus Data and store it in a map
650 using GetAllResultType =
651 std::vector<std::pair<std::string, std::variant<Binary>>>;
652 using IntfPropMap = std::map<std::string, GetAllResultType>;
653
654 IntfPropMap svpdBusData;
655
656 const auto vsys = getAllDBusProperty<GetAllResultType>(
657 constants::pimIntf,
658 "/xyz/openbmc_project/inventory/system/chassis/motherboard",
659 "com.ibm.ipzvpd.VSYS");
660 svpdBusData.emplace("VSYS", vsys);
661
662 const auto vcen = getAllDBusProperty<GetAllResultType>(
663 constants::pimIntf,
664 "/xyz/openbmc_project/inventory/system/chassis/motherboard",
665 "com.ibm.ipzvpd.VCEN");
666 svpdBusData.emplace("VCEN", vcen);
667
668 const auto lxr0 = getAllDBusProperty<GetAllResultType>(
669 constants::pimIntf,
670 "/xyz/openbmc_project/inventory/system/chassis/motherboard",
671 "com.ibm.ipzvpd.LXR0");
672 svpdBusData.emplace("LXR0", lxr0);
673
674 const auto util = getAllDBusProperty<GetAllResultType>(
675 constants::pimIntf,
676 "/xyz/openbmc_project/inventory/system/chassis/motherboard",
677 "com.ibm.ipzvpd.UTIL");
678 svpdBusData.emplace("UTIL", util);
679
680 for (const auto& recordKw : svpdKwdMap)
681 {
682 string record = recordKw.first;
683
684 // Extract specific record data from the svpdBusData map.
685 const auto& rec = svpdBusData.find(record);
686
687 if (rec == svpdBusData.end())
688 {
689 std::cerr << record << " not a part of critical system VPD records."
690 << std::endl;
691 continue;
692 }
693
694 const auto& recData = svpdBusData.find(record)->second;
695
696 string busStr{}, hwValStr{};
697 string mismatch = "NO"; // no mismatch
698
699 for (const auto& keyword : recordKw.second)
700 {
701 string hardwareValue{};
702 auto recItr = vpdMap.find(record);
703
704 if (recItr != vpdMap.end())
705 {
706 DbusPropertyMap& kwValMap = recItr->second;
707 auto kwItr = kwValMap.find(keyword);
708 if (kwItr != kwValMap.end())
709 {
710 hardwareValue = kwItr->second;
711 }
712 }
713
714 std::variant<Binary> kwValue;
715 for (auto& kwData : recData)
716 {
717 if (kwData.first == keyword)
718 {
719 kwValue = kwData.second;
720 break;
721 }
722 }
723
724 if (keyword != "SE")
725 {
726 ostringstream hwValStream;
727 hwValStream << "0x";
728 hwValStr = hwValStream.str();
729
730 for (uint16_t byte : hardwareValue)
731 {
732 hwValStream << setfill('0') << setw(2) << hex << byte;
733 hwValStr = hwValStream.str();
734 }
735
736 if (const auto value = get_if<Binary>(&kwValue))
737 {
738 busStr = byteArrayToHexString(*value);
739 }
740 if (busStr != hwValStr)
741 {
742 mismatch = "YES";
743 }
744 }
745 else
746 {
747 if (const auto value = get_if<Binary>(&kwValue))
748 {
749 busStr = getPrintableValue(*value);
750 }
751 if (busStr != hardwareValue)
752 {
753 mismatch = "YES";
754 }
755 hwValStr = hardwareValue;
756 }
757 recKwData.push_back(
758 make_tuple(++num, record, keyword, busStr, hwValStr, mismatch));
759 cout << left << setw(6) << num << left << setw(8) << record << left
760 << setw(9) << keyword << left << setw(30) << setfill(' ')
761 << busStr << left << setw(30) << setfill(' ') << hwValStr
762 << left << setw(14) << mismatch;
763
764 cout << "\n|--------------------------------------------------"
765 "----------------------------------------------------|"
766 << endl;
767 }
768 }
769 parseSVPDOptions(js);
770 return 0;
771}
772
773void VpdTool::parseSVPDOptions(const nlohmann::json& json)
774{
775 do
776 {
777 printFixSystemVPDOption(VpdTool::BMC_DATA_FOR_ALL);
778 printFixSystemVPDOption(VpdTool::SYSTEM_BACKPLANE_DATA_FOR_ALL);
779 printFixSystemVPDOption(VpdTool::MORE_OPTIONS);
780 printFixSystemVPDOption(VpdTool::EXIT);
781
782 int option = 0;
783 cin >> option;
784 cout << "\n|==========================================================="
785 "===========================================|"
786 << endl;
787
788 if (json.find("frus") == json.end())
789 {
790 throw runtime_error("Frus not found in json");
791 }
792
793 bool mismatchFound = false;
794
795 if (option == VpdTool::BMC_DATA_FOR_ALL)
796 {
797 for (const auto& data : recKwData)
798 {
799 if (get<5>(data) == "YES")
800 {
801 EditorImpl edit(constants::systemVpdFilePath, json,
802 get<1>(data), get<2>(data));
803 edit.updateKeyword(toBinary(get<3>(data)), 0, true);
804 mismatchFound = true;
805 }
806 }
807
808 if (mismatchFound)
809 {
810 cout << "\nData updated successfully for all mismatching "
811 "record-keyword pairs by choosing their corresponding "
812 "data on BMC. Exit successfully.\n"
813 << endl;
814 }
815 else
816 {
817 cout << "\nNo mismatch found for any of the above mentioned "
818 "record-keyword pair. Exit successfully.\n";
819 }
820
821 exit(0);
822 }
823 else if (option == VpdTool::SYSTEM_BACKPLANE_DATA_FOR_ALL)
824 {
825 for (const auto& data : recKwData)
826 {
827 if (get<5>(data) == "YES")
828 {
829 EditorImpl edit(constants::systemVpdFilePath, json,
830 get<1>(data), get<2>(data));
831 edit.updateKeyword(toBinary(get<4>(data)), 0, true);
832 mismatchFound = true;
833 }
834 }
835
836 if (mismatchFound)
837 {
838 cout << "\nData updated successfully for all mismatching "
839 "record-keyword pairs by choosing their corresponding "
840 "data on System Backplane.\n"
841 << endl;
842 }
843 else
844 {
845 cout << "\nNo mismatch found for any of the above mentioned "
846 "record-keyword pair. Exit successfully.\n";
847 }
848
849 exit(0);
850 }
851 else if (option == VpdTool::MORE_OPTIONS)
852 {
853 cout << "\nIterate through all restorable record-keyword pairs\n";
854
855 for (const auto& data : recKwData)
856 {
857 do
858 {
859 cout << "\n|==============================================="
860 "=================================================="
861 "=====|"
862 << endl;
863
864 cout << left << setw(6) << "S.No" << left << setw(8)
865 << "Record" << left << setw(9) << "Keyword" << left
866 << setw(30) << setfill(' ') << "Data On BMC" << left
867 << setw(30) << setfill(' ')
868 << "Data On System Backplane" << left << setw(14)
869 << "Data Mismatch" << endl;
870
871 cout << left << setw(6) << get<0>(data) << left << setw(8)
872 << get<1>(data) << left << setw(9) << get<2>(data)
873 << left << setw(30) << setfill(' ') << get<3>(data)
874 << left << setw(30) << setfill(' ') << get<4>(data)
875 << left << setw(14) << get<5>(data);
876
877 cout << "\n|==============================================="
878 "=================================================="
879 "=====|"
880 << endl;
881
882 if (get<5>(data) == "NO")
883 {
884 cout << "\nNo mismatch found.\n";
885 printFixSystemVPDOption(VpdTool::NEW_VALUE_ON_BOTH);
886 printFixSystemVPDOption(VpdTool::SKIP_CURRENT);
887 printFixSystemVPDOption(VpdTool::EXIT);
888 }
889 else
890 {
891 printFixSystemVPDOption(VpdTool::BMC_DATA_FOR_CURRENT);
892 printFixSystemVPDOption(
893 VpdTool::SYSTEM_BACKPLANE_DATA_FOR_CURRENT);
894 printFixSystemVPDOption(VpdTool::NEW_VALUE_ON_BOTH);
895 printFixSystemVPDOption(VpdTool::SKIP_CURRENT);
896 printFixSystemVPDOption(VpdTool::EXIT);
897 }
898
899 cin >> option;
900
901 cout << "\n|==============================================="
902 "=================================================="
903 "=====|"
904 << endl;
905
906 EditorImpl edit(constants::systemVpdFilePath, json,
907 get<1>(data), get<2>(data));
908
909 if (option == VpdTool::BMC_DATA_FOR_CURRENT)
910 {
911 edit.updateKeyword(toBinary(get<3>(data)), 0, true);
912 cout << "\nData updated successfully.\n";
913 break;
914 }
915 else if (option ==
916 VpdTool::SYSTEM_BACKPLANE_DATA_FOR_CURRENT)
917 {
918 edit.updateKeyword(toBinary(get<4>(data)), 0, true);
919 cout << "\nData updated successfully.\n";
920 break;
921 }
922 else if (option == VpdTool::NEW_VALUE_ON_BOTH)
923 {
924 string value;
925 cout << "\nEnter the new value to update both on BMC & "
926 "System Backplane (Value should be in ASCII or "
927 "in HEX(prefixed with 0x)) : ";
928 cin >> value;
929 cout << "\n|==========================================="
930 "=============================================="
931 "=============|"
932 << endl;
933
934 edit.updateKeyword(toBinary(value), 0, true);
935 cout << "\nData updated successfully.\n";
936 break;
937 }
938 else if (option == VpdTool::SKIP_CURRENT)
939 {
940 cout << "\nSkipped the above record-keyword pair. "
941 "Continue to the next available pair.\n";
942 break;
943 }
944 else if (option == VpdTool::EXIT)
945 {
946 cout << "\nExit successfully\n";
947 exit(0);
948 }
949 else
950 {
951 cout << "\nProvide a valid option. Retrying for the "
952 "current record-keyword pair\n";
953 }
954 } while (1);
955 }
956 exit(0);
957 }
958 else if (option == VpdTool::EXIT)
959 {
960 cout << "\nExit successfully";
961 exit(0);
962 }
963 else
964 {
965 cout << "\nProvide a valid option. Retry.";
966 continue;
967 }
968
969 } while (true);
970}