blob: ef7ad0bf830c6fe4828d15fadd1f3ea26416880a [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 }
Sunny Srivastavaf31a91b2022-06-09 08:11:29 -0500533
534 const std::string& inventoryPath =
535 jsonFile["frus"][fruPath][0]["inventoryPath"];
536
537 Impl obj(completeVPDFile, (constants::pimPath + inventoryPath));
Priyanga Ramasamy38031312021-10-07 16:39:13 -0500538 std::string keywordVal = obj.readKwFromHw(recordName, keyword);
539
540 if (!keywordVal.empty())
541 {
542 json output = json::object({});
543 json kwVal = json::object({});
544 kwVal.emplace(keyword, keywordVal);
545
546 output.emplace(fruPath, kwVal);
547
548 debugger(output);
549 }
550 else
551 {
552 std::cerr << "The given keyword " << keyword << " or record "
553 << recordName
554 << " or both are not present in the given FRU path "
555 << fruPath << std::endl;
556 }
557}
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500558
559void VpdTool::printFixSystemVPDOption(UserOption option)
560{
561 switch (option)
562 {
563 case VpdTool::EXIT:
564 cout << "\nEnter 0 => To exit successfully : ";
565 break;
566 case VpdTool::BMC_DATA_FOR_ALL:
567 cout << "\n\nEnter 1 => If you choose the data on BMC for all "
568 "mismatching record-keyword pairs";
569 break;
570 case VpdTool::SYSTEM_BACKPLANE_DATA_FOR_ALL:
571 cout << "\nEnter 2 => If you choose the data on System "
572 "Backplane for all mismatching record-keyword pairs";
573 break;
574 case VpdTool::MORE_OPTIONS:
575 cout << "\nEnter 3 => If you wish to explore more options";
576 break;
577 case VpdTool::BMC_DATA_FOR_CURRENT:
578 cout << "\nEnter 4 => If you choose the data on BMC as the "
579 "right value";
580 break;
581 case VpdTool::SYSTEM_BACKPLANE_DATA_FOR_CURRENT:
582 cout << "\nEnter 5 => If you choose the data on System "
583 "Backplane as the right value";
584 break;
585 case VpdTool::NEW_VALUE_ON_BOTH:
586 cout << "\nEnter 6 => If you wish to enter a new value to "
587 "update both on BMC and System Backplane";
588 break;
589 case VpdTool::SKIP_CURRENT:
590 cout << "\nEnter 7 => If you wish to skip the above "
591 "record-keyword pair";
592 break;
593 }
594}
595
596int VpdTool::fixSystemVPD()
597{
Priyanga Ramasamy0ac10852022-10-26 05:35:42 -0500598 std::string outline(191, '=');
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500599 cout << "\nRestorable record-keyword pairs and their data on BMC & "
Priyanga Ramasamy0ac10852022-10-26 05:35:42 -0500600 "System Backplane.\n\n"
601 << outline << std::endl;
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500602
603 cout << left << setw(6) << "S.No" << left << setw(8) << "Record" << left
Priyanga Ramasamy0ac10852022-10-26 05:35:42 -0500604 << setw(9) << "Keyword" << left << setw(75) << "Data On BMC" << left
605 << setw(75) << "Data On System Backplane" << left << setw(14)
606 << "Data Mismatch\n"
607 << outline << std::endl;
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500608
609 int num = 0;
610
611 // Get system VPD data in map
612 Binary vpdVector{};
613 json js{};
614
615 auto jsonToParse = INVENTORY_JSON_DEFAULT;
616 if (fs::exists(INVENTORY_JSON_SYM_LINK))
617 {
618 jsonToParse = INVENTORY_JSON_SYM_LINK;
619 }
620
621 ifstream inventoryJson(jsonToParse);
622 if (!inventoryJson)
623 {
624 throw runtime_error("VPD JSON file not found");
625 }
626 js = json::parse(inventoryJson);
627
628 vpdVector = getVpdDataInVector(js, constants::systemVpdFilePath);
Sunny Srivastavaf31a91b2022-06-09 08:11:29 -0500629 ParserInterface* parser = ParserFactory::getParser(
630 vpdVector, constants::pimPath + std::string(constants::SYSTEM_OBJECT));
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500631 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
Priyanga Ramasamy952d6c52022-11-07 07:20:24 -0600699 for (const auto& keywordInfo : recordKw.second)
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500700 {
Priyanga Ramasamy952d6c52022-11-07 07:20:24 -0600701 const auto& keyword = get<0>(keywordInfo);
702
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500703 string hardwareValue{};
704 auto recItr = vpdMap.find(record);
705
706 if (recItr != vpdMap.end())
707 {
708 DbusPropertyMap& kwValMap = recItr->second;
709 auto kwItr = kwValMap.find(keyword);
710 if (kwItr != kwValMap.end())
711 {
712 hardwareValue = kwItr->second;
713 }
714 }
715
716 std::variant<Binary> kwValue;
717 for (auto& kwData : recData)
718 {
719 if (kwData.first == keyword)
720 {
721 kwValue = kwData.second;
722 break;
723 }
724 }
725
726 if (keyword != "SE")
727 {
728 ostringstream hwValStream;
729 hwValStream << "0x";
730 hwValStr = hwValStream.str();
731
732 for (uint16_t byte : hardwareValue)
733 {
734 hwValStream << setfill('0') << setw(2) << hex << byte;
735 hwValStr = hwValStream.str();
736 }
737
738 if (const auto value = get_if<Binary>(&kwValue))
739 {
740 busStr = byteArrayToHexString(*value);
741 }
742 if (busStr != hwValStr)
743 {
744 mismatch = "YES";
745 }
746 }
747 else
748 {
749 if (const auto value = get_if<Binary>(&kwValue))
750 {
751 busStr = getPrintableValue(*value);
752 }
753 if (busStr != hardwareValue)
754 {
755 mismatch = "YES";
756 }
757 hwValStr = hardwareValue;
758 }
759 recKwData.push_back(
760 make_tuple(++num, record, keyword, busStr, hwValStr, mismatch));
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500761
Priyanga Ramasamy0ac10852022-10-26 05:35:42 -0500762 std::string splitLine(191, '-');
763 cout << left << setw(6) << num << left << setw(8) << record << left
764 << setw(9) << keyword << left << setw(75) << setfill(' ')
765 << busStr << left << setw(75) << setfill(' ') << hwValStr
766 << left << setw(14) << mismatch << '\n'
767 << splitLine << endl;
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500768 }
769 }
770 parseSVPDOptions(js);
771 return 0;
772}
773
774void VpdTool::parseSVPDOptions(const nlohmann::json& json)
775{
776 do
777 {
778 printFixSystemVPDOption(VpdTool::BMC_DATA_FOR_ALL);
779 printFixSystemVPDOption(VpdTool::SYSTEM_BACKPLANE_DATA_FOR_ALL);
780 printFixSystemVPDOption(VpdTool::MORE_OPTIONS);
781 printFixSystemVPDOption(VpdTool::EXIT);
782
783 int option = 0;
784 cin >> option;
Priyanga Ramasamy0ac10852022-10-26 05:35:42 -0500785
786 std::string outline(191, '=');
787 cout << '\n' << outline << endl;
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500788
789 if (json.find("frus") == json.end())
790 {
791 throw runtime_error("Frus not found in json");
792 }
793
794 bool mismatchFound = false;
795
796 if (option == VpdTool::BMC_DATA_FOR_ALL)
797 {
798 for (const auto& data : recKwData)
799 {
800 if (get<5>(data) == "YES")
801 {
802 EditorImpl edit(constants::systemVpdFilePath, json,
803 get<1>(data), get<2>(data));
804 edit.updateKeyword(toBinary(get<3>(data)), 0, true);
805 mismatchFound = true;
806 }
807 }
808
809 if (mismatchFound)
810 {
811 cout << "\nData updated successfully for all mismatching "
812 "record-keyword pairs by choosing their corresponding "
813 "data on BMC. Exit successfully.\n"
814 << endl;
815 }
816 else
817 {
818 cout << "\nNo mismatch found for any of the above mentioned "
819 "record-keyword pair. Exit successfully.\n";
820 }
821
822 exit(0);
823 }
824 else if (option == VpdTool::SYSTEM_BACKPLANE_DATA_FOR_ALL)
825 {
826 for (const auto& data : recKwData)
827 {
828 if (get<5>(data) == "YES")
829 {
830 EditorImpl edit(constants::systemVpdFilePath, json,
831 get<1>(data), get<2>(data));
832 edit.updateKeyword(toBinary(get<4>(data)), 0, true);
833 mismatchFound = true;
834 }
835 }
836
837 if (mismatchFound)
838 {
839 cout << "\nData updated successfully for all mismatching "
840 "record-keyword pairs by choosing their corresponding "
841 "data on System Backplane.\n"
842 << endl;
843 }
844 else
845 {
846 cout << "\nNo mismatch found for any of the above mentioned "
847 "record-keyword pair. Exit successfully.\n";
848 }
849
850 exit(0);
851 }
852 else if (option == VpdTool::MORE_OPTIONS)
853 {
854 cout << "\nIterate through all restorable record-keyword pairs\n";
855
856 for (const auto& data : recKwData)
857 {
858 do
859 {
Priyanga Ramasamy0ac10852022-10-26 05:35:42 -0500860 cout << '\n' << outline << endl;
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500861
862 cout << left << setw(6) << "S.No" << left << setw(8)
863 << "Record" << left << setw(9) << "Keyword" << left
Priyanga Ramasamy0ac10852022-10-26 05:35:42 -0500864 << setw(75) << setfill(' ') << "Data On BMC" << left
865 << setw(75) << setfill(' ')
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500866 << "Data On System Backplane" << left << setw(14)
867 << "Data Mismatch" << endl;
868
869 cout << left << setw(6) << get<0>(data) << left << setw(8)
870 << get<1>(data) << left << setw(9) << get<2>(data)
Priyanga Ramasamy0ac10852022-10-26 05:35:42 -0500871 << left << setw(75) << setfill(' ') << get<3>(data)
872 << left << setw(75) << setfill(' ') << get<4>(data)
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500873 << left << setw(14) << get<5>(data);
874
Priyanga Ramasamy0ac10852022-10-26 05:35:42 -0500875 cout << '\n' << outline << endl;
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500876
877 if (get<5>(data) == "NO")
878 {
879 cout << "\nNo mismatch found.\n";
880 printFixSystemVPDOption(VpdTool::NEW_VALUE_ON_BOTH);
881 printFixSystemVPDOption(VpdTool::SKIP_CURRENT);
882 printFixSystemVPDOption(VpdTool::EXIT);
883 }
884 else
885 {
886 printFixSystemVPDOption(VpdTool::BMC_DATA_FOR_CURRENT);
887 printFixSystemVPDOption(
888 VpdTool::SYSTEM_BACKPLANE_DATA_FOR_CURRENT);
889 printFixSystemVPDOption(VpdTool::NEW_VALUE_ON_BOTH);
890 printFixSystemVPDOption(VpdTool::SKIP_CURRENT);
891 printFixSystemVPDOption(VpdTool::EXIT);
892 }
893
894 cin >> option;
Priyanga Ramasamy0ac10852022-10-26 05:35:42 -0500895 cout << '\n' << outline << endl;
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500896
897 EditorImpl edit(constants::systemVpdFilePath, json,
898 get<1>(data), get<2>(data));
899
900 if (option == VpdTool::BMC_DATA_FOR_CURRENT)
901 {
902 edit.updateKeyword(toBinary(get<3>(data)), 0, true);
903 cout << "\nData updated successfully.\n";
904 break;
905 }
906 else if (option ==
907 VpdTool::SYSTEM_BACKPLANE_DATA_FOR_CURRENT)
908 {
909 edit.updateKeyword(toBinary(get<4>(data)), 0, true);
910 cout << "\nData updated successfully.\n";
911 break;
912 }
913 else if (option == VpdTool::NEW_VALUE_ON_BOTH)
914 {
915 string value;
916 cout << "\nEnter the new value to update both on BMC & "
917 "System Backplane (Value should be in ASCII or "
918 "in HEX(prefixed with 0x)) : ";
919 cin >> value;
Priyanga Ramasamy0ac10852022-10-26 05:35:42 -0500920 cout << '\n' << outline << endl;
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500921
922 edit.updateKeyword(toBinary(value), 0, true);
923 cout << "\nData updated successfully.\n";
924 break;
925 }
926 else if (option == VpdTool::SKIP_CURRENT)
927 {
928 cout << "\nSkipped the above record-keyword pair. "
929 "Continue to the next available pair.\n";
930 break;
931 }
932 else if (option == VpdTool::EXIT)
933 {
934 cout << "\nExit successfully\n";
935 exit(0);
936 }
937 else
938 {
939 cout << "\nProvide a valid option. Retrying for the "
940 "current record-keyword pair\n";
941 }
942 } while (1);
943 }
944 exit(0);
945 }
946 else if (option == VpdTool::EXIT)
947 {
948 cout << "\nExit successfully";
949 exit(0);
950 }
951 else
952 {
953 cout << "\nProvide a valid option. Retry.";
954 continue;
955 }
956
957 } while (true);
Priyanga Ramasamy952d6c52022-11-07 07:20:24 -0600958}