blob: 753181dfa9810261d461d74c8ae116e379ae8eb3 [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
girik18bb9852022-11-16 05:48:13 -060053 uint32_t vpdStartOffset = 0;
Priyanga Ramasamy6d5e7342022-10-14 07:17:25 -050054 vpdVector = getVpdDataInVector(js, constants::systemVpdFilePath);
girik18bb9852022-11-16 05:48:13 -060055 ParserInterface* parser = ParserFactory::getParser(
56 vpdVector, invPath, constants::systemVpdFilePath, vpdStartOffset);
Priyanga Ramasamy6d5e7342022-10-14 07:17:25 -050057 auto parseResult = parser->parse();
58 ParserFactory::freeParser(parser);
59
60 if (auto pVal = std::get_if<Store>(&parseResult))
61 {
62 vpdMap = pVal->getVpdMap();
63 }
64 else
65 {
66 std::string err =
67 vpdPath + " is not of type IPZ VPD. Unable to parse the VPD.";
68 throw std::runtime_error(err);
69 }
70}
71
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +053072Binary VpdTool::toBinary(const std::string& value)
73{
74 Binary val{};
75 if (value.find("0x") == string::npos)
76 {
77 val.assign(value.begin(), value.end());
78 }
79 else if (value.find("0x") != string::npos)
80 {
81 stringstream ss;
82 ss.str(value.substr(2));
83 string byteStr{};
84
Priyanga Ramasamyec912e62021-12-15 22:47:51 -060085 if (value.length() % 2 != 0)
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +053086 {
Priyanga Ramasamyec912e62021-12-15 22:47:51 -060087 throw runtime_error(
88 "VPD-TOOL write option accepts 2 digit hex numbers. (Eg. 0x1 "
89 "should be given as 0x01). Aborting the write operation.");
90 }
91
92 if (value.find_first_not_of("0123456789abcdefABCDEF", 2) !=
93 std::string::npos)
94 {
95 throw runtime_error("Provide a valid hexadecimal input.");
96 }
97
98 while (ss >> setw(2) >> byteStr)
99 {
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +0530100 uint8_t byte = strtoul(byteStr.c_str(), nullptr, 16);
101
102 val.push_back(byte);
103 }
104 }
105
106 else
107 {
108 throw runtime_error("The value to be updated should be either in ascii "
109 "or in hex. Refer --help option");
110 }
111 return val;
112}
PriyangaRamasamycdf943c2020-03-18 02:25:30 +0530113
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600114void VpdTool::printReturnCode(int returnCode)
115{
116 if (returnCode)
117 {
118 cout << "\n Command failed with the return code " << returnCode
119 << ". Continuing the execution. " << endl;
120 }
121}
122
PriyangaRamasamycdf943c2020-03-18 02:25:30 +0530123void VpdTool::eraseInventoryPath(string& fru)
124{
125 // Power supply frupath comes with INVENTORY_PATH appended in prefix.
126 // Stripping it off inorder to avoid INVENTORY_PATH duplication
127 // during getVINIProperties() execution.
128 fru.erase(0, sizeof(INVENTORY_PATH) - 1);
129}
130
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530131void VpdTool::debugger(json output)
132{
133 cout << output.dump(4) << '\n';
134}
135
136auto VpdTool::makeDBusCall(const string& objectName, const string& interface,
137 const string& kw)
138{
139 auto bus = sdbusplus::bus::new_default();
140 auto properties =
141 bus.new_method_call(INVENTORY_MANAGER_SERVICE, objectName.c_str(),
142 "org.freedesktop.DBus.Properties", "Get");
143 properties.append(interface);
144 properties.append(kw);
145 auto result = bus.call(properties);
146
147 if (result.is_method_error())
148 {
149 throw runtime_error("Get api failed");
150 }
151 return result;
152}
153
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500154json VpdTool::getVINIProperties(string invPath)
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530155{
156 variant<Binary> response;
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530157 json kwVal = json::object({});
158
159 vector<string> keyword{"CC", "SN", "PN", "FN", "DR"};
160 string interface = "com.ibm.ipzvpd.VINI";
PriyangaRamasamycdf943c2020-03-18 02:25:30 +0530161 string objectName = {};
162
163 if (invPath.find(INVENTORY_PATH) != string::npos)
164 {
165 objectName = invPath;
166 eraseInventoryPath(invPath);
167 }
168 else
169 {
170 objectName = INVENTORY_PATH + invPath;
171 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530172 for (string kw : keyword)
173 {
174 try
175 {
176 makeDBusCall(objectName, interface, kw).read(response);
177
178 if (auto vec = get_if<Binary>(&response))
179 {
PriyangaRamasamy887a42a2020-09-03 00:33:57 +0530180 string printableVal = getPrintableValue(*vec);
181 kwVal.emplace(kw, printableVal);
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530182 }
183 }
Patrick Williams2eb01762022-07-22 19:26:56 -0500184 catch (const sdbusplus::exception_t& e)
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530185 {
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500186 if (string(e.name()) ==
187 string("org.freedesktop.DBus.Error.UnknownObject"))
188 {
189 kwVal.emplace(invPath, json::object({}));
190 objFound = false;
191 break;
192 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530193 }
194 }
195
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500196 return kwVal;
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530197}
198
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500199void VpdTool::getExtraInterfaceProperties(const string& invPath,
200 const string& extraInterface,
201 const json& prop, json& output)
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530202{
203 variant<string> response;
204
205 string objectName = INVENTORY_PATH + invPath;
206
207 for (const auto& itProp : prop.items())
208 {
209 string kw = itProp.key();
210 try
211 {
212 makeDBusCall(objectName, extraInterface, kw).read(response);
213
214 if (auto str = get_if<string>(&response))
215 {
216 output.emplace(kw, *str);
217 }
218 }
Patrick Williams2eb01762022-07-22 19:26:56 -0500219 catch (const sdbusplus::exception_t& e)
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530220 {
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500221 if (std::string(e.name()) ==
222 std::string("org.freedesktop.DBus.Error.UnknownObject"))
223 {
224 objFound = false;
225 break;
226 }
227 else if (std::string(e.name()) ==
228 std::string("org.freedesktop.DBus.Error.UnknownProperty"))
229 {
230 output.emplace(kw, "");
231 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530232 }
233 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530234}
235
236json VpdTool::interfaceDecider(json& itemEEPROM)
237{
238 if (itemEEPROM.find("inventoryPath") == itemEEPROM.end())
239 {
240 throw runtime_error("Inventory Path not found");
241 }
242
243 if (itemEEPROM.find("extraInterfaces") == itemEEPROM.end())
244 {
245 throw runtime_error("Extra Interfaces not found");
246 }
247
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500248 json subOutput = json::object({});
Alpana Kumarib6965f12020-06-01 00:32:21 -0500249 fruType = "FRU";
250
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500251 json j;
252 objFound = true;
253 string invPath = itemEEPROM.at("inventoryPath");
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530254
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500255 j = getVINIProperties(invPath);
256
257 if (objFound)
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530258 {
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500259 subOutput.insert(j.begin(), j.end());
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530260 json js;
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500261 if (itemEEPROM.find("type") != itemEEPROM.end())
262 {
263 fruType = itemEEPROM.at("type");
264 }
265 js.emplace("TYPE", fruType);
266
267 if (invPath.find("powersupply") != string::npos)
268 {
269 js.emplace("type", POWER_SUPPLY_TYPE_INTERFACE);
270 }
271 else if (invPath.find("fan") != string::npos)
272 {
273 js.emplace("type", FAN_INTERFACE);
274 }
275
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530276 for (const auto& ex : itemEEPROM["extraInterfaces"].items())
277 {
278 if (!(ex.value().is_null()))
279 {
Priyanga Ramasamydacaa472021-10-07 12:22:41 -0500280 // TODO: Remove this if condition check once inventory json is
281 // updated with xyz location code interface.
282 if (ex.key() == "com.ibm.ipzvpd.Location")
283 {
284 getExtraInterfaceProperties(
285 invPath,
286 "xyz.openbmc_project.Inventory.Decorator.LocationCode",
287 ex.value(), js);
288 }
289 else
290 {
291 getExtraInterfaceProperties(invPath, ex.key(), ex.value(),
292 js);
293 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530294 }
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500295 if ((ex.key().find("Item") != string::npos) &&
296 (ex.value().is_null()))
297 {
298 js.emplace("type", ex.key());
299 }
300 subOutput.insert(js.begin(), js.end());
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530301 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530302 }
Priyanga Ramasamy0086dd12021-09-28 10:31:50 -0500303 return subOutput;
304}
305
306json VpdTool::getPresentPropJson(const std::string& invPath,
307 std::string& parentPresence)
308{
309 std::variant<bool> response;
310 makeDBusCall(invPath, "xyz.openbmc_project.Inventory.Item", "Present")
311 .read(response);
312
313 std::string presence{};
314
315 if (auto pVal = get_if<bool>(&response))
316 {
317 presence = *pVal ? "true" : "false";
318 if (parentPresence.empty())
319 {
320 parentPresence = presence;
321 }
322 }
323 else
324 {
325 presence = parentPresence;
326 }
327
328 json js;
329 js.emplace("Present", presence);
330 return js;
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530331}
332
333json VpdTool::parseInvJson(const json& jsObject, char flag, string fruPath)
334{
335 json output = json::object({});
336 bool validObject = false;
337
338 if (jsObject.find("frus") == jsObject.end())
339 {
340 throw runtime_error("Frus missing in Inventory json");
341 }
342 else
343 {
344 for (const auto& itemFRUS : jsObject["frus"].items())
345 {
Priyanga Ramasamy0086dd12021-09-28 10:31:50 -0500346 string parentPresence{};
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530347 for (auto itemEEPROM : itemFRUS.value())
348 {
Priyanga Ramasamy0086dd12021-09-28 10:31:50 -0500349 json subOutput = json::object({});
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530350 try
351 {
352 if (flag == 'O')
353 {
354 if (itemEEPROM.find("inventoryPath") ==
355 itemEEPROM.end())
356 {
357 throw runtime_error("Inventory Path not found");
358 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530359 else if (itemEEPROM.at("inventoryPath") == fruPath)
360 {
361 validObject = true;
Priyanga Ramasamy0086dd12021-09-28 10:31:50 -0500362 subOutput = interfaceDecider(itemEEPROM);
363 json presentJs = getPresentPropJson(
364 "/xyz/openbmc_project/inventory" + fruPath,
365 parentPresence);
366 subOutput.insert(presentJs.begin(),
367 presentJs.end());
368 output.emplace(fruPath, subOutput);
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530369 return output;
370 }
Priyanga Ramasamy0086dd12021-09-28 10:31:50 -0500371 else // this else is to keep track of parent present
372 // property.
373 {
374 json presentJs = getPresentPropJson(
375 "/xyz/openbmc_project/inventory" +
376 string(itemEEPROM.at("inventoryPath")),
377 parentPresence);
378 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530379 }
380 else
381 {
Priyanga Ramasamy0086dd12021-09-28 10:31:50 -0500382 subOutput = interfaceDecider(itemEEPROM);
383 json presentJs = getPresentPropJson(
384 "/xyz/openbmc_project/inventory" +
385 string(itemEEPROM.at("inventoryPath")),
386 parentPresence);
387 subOutput.insert(presentJs.begin(), presentJs.end());
388 output.emplace(string(itemEEPROM.at("inventoryPath")),
389 subOutput);
390 }
391 }
392 catch (const sdbusplus::exception::SdBusError& e)
393 {
394 // if any of frupath doesn't have Present property of its
395 // own, emplace its parent's present property value.
396 if (e.name() == std::string("org.freedesktop.DBus.Error."
397 "UnknownProperty") &&
398 (((flag == 'O') && validObject) || flag == 'I'))
399 {
400 json presentJs;
401 presentJs.emplace("Present", parentPresence);
402 subOutput.insert(presentJs.begin(), presentJs.end());
403 output.emplace(string(itemEEPROM.at("inventoryPath")),
404 subOutput);
405 }
406
407 // for the user given child frupath which doesn't have
408 // Present prop (vpd-tool -o).
409 if ((flag == 'O') && validObject)
410 {
411 return output;
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530412 }
413 }
Patrick Williams8e15b932021-10-06 13:04:22 -0500414 catch (const exception& e)
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530415 {
416 cerr << e.what();
417 }
418 }
419 }
420 if ((flag == 'O') && (!validObject))
421 {
422 throw runtime_error(
423 "Invalid object path. Refer --dumpInventory/-i option.");
424 }
425 }
426 return output;
427}
428
429void VpdTool::dumpInventory(const nlohmann::basic_json<>& jsObject)
430{
431 char flag = 'I';
PriyangaRamasamycdf943c2020-03-18 02:25:30 +0530432 json output = json::array({});
433 output.emplace_back(parseInvJson(jsObject, flag, ""));
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530434 debugger(output);
435}
436
437void VpdTool::dumpObject(const nlohmann::basic_json<>& jsObject)
438{
439 char flag = 'O';
PriyangaRamasamycdf943c2020-03-18 02:25:30 +0530440 json output = json::array({});
Santosh Puranikd5d52bb2020-07-28 15:08:10 +0530441 output.emplace_back(parseInvJson(jsObject, flag, fruPath));
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530442 debugger(output);
443}
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530444
445void VpdTool::readKeyword()
446{
447 string interface = "com.ibm.ipzvpd.";
448 variant<Binary> response;
449
450 try
451 {
452 json output = json::object({});
453 json kwVal = json::object({});
454 makeDBusCall(INVENTORY_PATH + fruPath, interface + recordName, keyword)
455 .read(response);
456
PriyangaRamasamy887a42a2020-09-03 00:33:57 +0530457 string printableVal{};
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530458 if (auto vec = get_if<Binary>(&response))
459 {
PriyangaRamasamy887a42a2020-09-03 00:33:57 +0530460 printableVal = getPrintableValue(*vec);
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530461 }
PriyangaRamasamy887a42a2020-09-03 00:33:57 +0530462 kwVal.emplace(keyword, printableVal);
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530463
464 output.emplace(fruPath, kwVal);
465
466 debugger(output);
467 }
Patrick Williams8e15b932021-10-06 13:04:22 -0500468 catch (const json::exception& e)
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530469 {
470 json output = json::object({});
471 json kwVal = json::object({});
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530472 }
473}
PriyangaRamasamyd09d2ec2020-03-12 14:11:50 +0530474
475int VpdTool::updateKeyword()
476{
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +0530477 Binary val = toBinary(value);
PriyangaRamasamyd09d2ec2020-03-12 14:11:50 +0530478 auto bus = sdbusplus::bus::new_default();
479 auto properties =
480 bus.new_method_call(BUSNAME, OBJPATH, IFACE, "WriteKeyword");
481 properties.append(static_cast<sdbusplus::message::object_path>(fruPath));
482 properties.append(recordName);
483 properties.append(keyword);
484 properties.append(val);
485 auto result = bus.call(properties);
486
487 if (result.is_method_error())
488 {
489 throw runtime_error("Get api failed");
490 }
491 return 0;
492}
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530493
494void VpdTool::forceReset(const nlohmann::basic_json<>& jsObject)
495{
496 for (const auto& itemFRUS : jsObject["frus"].items())
497 {
498 for (const auto& itemEEPROM : itemFRUS.value().items())
499 {
500 string fru = itemEEPROM.value().at("inventoryPath");
501
502 fs::path fruCachePath = INVENTORY_MANAGER_CACHE;
503 fruCachePath += INVENTORY_PATH;
504 fruCachePath += fru;
505
506 try
507 {
508 for (const auto& it : fs::directory_iterator(fruCachePath))
509 {
510 if (fs::is_regular_file(it.status()))
511 {
512 fs::remove(it);
513 }
514 }
515 }
516 catch (const fs::filesystem_error& e)
517 {
518 }
519 }
520 }
521
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600522 cout.flush();
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530523 string udevRemove = "udevadm trigger -c remove -s \"*nvmem*\" -v";
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600524 int returnCode = system(udevRemove.c_str());
525 printReturnCode(returnCode);
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530526
527 string invManagerRestart =
528 "systemctl restart xyz.openbmc_project.Inventory.Manager.service";
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600529 returnCode = system(invManagerRestart.c_str());
530 printReturnCode(returnCode);
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530531
Santosh Puranik6c7a84e2022-03-09 13:42:18 +0530532 string sysVpdRestart = "systemctl restart system-vpd.service";
533 returnCode = system(sysVpdRestart.c_str());
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600534 printReturnCode(returnCode);
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530535
536 string udevAdd = "udevadm trigger -c add -s \"*nvmem*\" -v";
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600537 returnCode = system(udevAdd.c_str());
538 printReturnCode(returnCode);
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530539}
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +0530540
Priyanga Ramasamyc99a0b02022-06-08 14:53:39 -0500541int VpdTool::updateHardware(const uint32_t offset)
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +0530542{
543 int rc = 0;
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +0530544 const Binary& val = static_cast<const Binary&>(toBinary(value));
545 ifstream inventoryJson(INVENTORY_JSON_SYM_LINK);
546 try
547 {
548 auto json = nlohmann::json::parse(inventoryJson);
549 EditorImpl edit(fruPath, json, recordName, keyword);
Priyanga Ramasamyc99a0b02022-06-08 14:53:39 -0500550
551 edit.updateKeyword(val, offset, false);
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +0530552 }
Patrick Williams8e15b932021-10-06 13:04:22 -0500553 catch (const json::parse_error& ex)
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +0530554 {
555 throw(VpdJsonException("Json Parsing failed", INVENTORY_JSON_SYM_LINK));
556 }
557 return rc;
Priyanga Ramasamy38031312021-10-07 16:39:13 -0500558}
559
Priyanga Ramasamyc99a0b02022-06-08 14:53:39 -0500560void VpdTool::readKwFromHw(const uint32_t& startOffset)
Priyanga Ramasamy38031312021-10-07 16:39:13 -0500561{
Priyanga Ramasamy38031312021-10-07 16:39:13 -0500562 ifstream inventoryJson(INVENTORY_JSON_SYM_LINK);
563 auto jsonFile = nlohmann::json::parse(inventoryJson);
564
Priyanga Ramasamy38031312021-10-07 16:39:13 -0500565 Binary completeVPDFile;
566 completeVPDFile.resize(65504);
567 fstream vpdFileStream;
568 vpdFileStream.open(fruPath,
569 std::ios::in | std::ios::out | std::ios::binary);
570
571 vpdFileStream.seekg(startOffset, ios_base::cur);
572 vpdFileStream.read(reinterpret_cast<char*>(&completeVPDFile[0]), 65504);
573 completeVPDFile.resize(vpdFileStream.gcount());
574 vpdFileStream.clear(std::ios_base::eofbit);
575
576 if (completeVPDFile.empty())
577 {
578 throw std::runtime_error("Invalid File");
579 }
Sunny Srivastavaf31a91b2022-06-09 08:11:29 -0500580
581 const std::string& inventoryPath =
582 jsonFile["frus"][fruPath][0]["inventoryPath"];
583
girik18bb9852022-11-16 05:48:13 -0600584 uint32_t vpdStartOffset = 0;
585 for (const auto& item : jsonFile["frus"][fruPath])
586 {
587 if (item.find("offset") != item.end())
588 {
589 vpdStartOffset = item["offset"];
590 }
591 }
592
593 Impl obj(completeVPDFile, (constants::pimPath + inventoryPath), fruPath,
594 vpdStartOffset);
Priyanga Ramasamy38031312021-10-07 16:39:13 -0500595 std::string keywordVal = obj.readKwFromHw(recordName, keyword);
596
597 if (!keywordVal.empty())
598 {
599 json output = json::object({});
600 json kwVal = json::object({});
601 kwVal.emplace(keyword, keywordVal);
602
603 output.emplace(fruPath, kwVal);
604
605 debugger(output);
606 }
607 else
608 {
609 std::cerr << "The given keyword " << keyword << " or record "
610 << recordName
611 << " or both are not present in the given FRU path "
612 << fruPath << std::endl;
613 }
614}
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500615
616void VpdTool::printFixSystemVPDOption(UserOption option)
617{
618 switch (option)
619 {
620 case VpdTool::EXIT:
621 cout << "\nEnter 0 => To exit successfully : ";
622 break;
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600623 case VpdTool::BACKUP_DATA_FOR_ALL:
624 cout << "\n\nEnter 1 => If you choose the data on backup for all "
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500625 "mismatching record-keyword pairs";
626 break;
627 case VpdTool::SYSTEM_BACKPLANE_DATA_FOR_ALL:
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600628 cout << "\nEnter 2 => If you choose the data on primary for all "
629 "mismatching record-keyword pairs";
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500630 break;
631 case VpdTool::MORE_OPTIONS:
632 cout << "\nEnter 3 => If you wish to explore more options";
633 break;
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600634 case VpdTool::BACKUP_DATA_FOR_CURRENT:
635 cout << "\nEnter 4 => If you choose the data on backup as the "
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500636 "right value";
637 break;
638 case VpdTool::SYSTEM_BACKPLANE_DATA_FOR_CURRENT:
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600639 cout << "\nEnter 5 => If you choose the data on primary as the "
640 "right value";
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500641 break;
642 case VpdTool::NEW_VALUE_ON_BOTH:
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600643 cout << "\nEnter 6 => If you wish to enter a new value to update "
644 "both on backup and primary";
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500645 break;
646 case VpdTool::SKIP_CURRENT:
647 cout << "\nEnter 7 => If you wish to skip the above "
648 "record-keyword pair";
649 break;
650 }
651}
652
Priyanga Ramasamy6d5e7342022-10-14 07:17:25 -0500653void VpdTool::getSystemDataFromCache(IntfPropMap& svpdBusData)
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500654{
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500655 const auto vsys = getAllDBusProperty<GetAllResultType>(
656 constants::pimIntf,
657 "/xyz/openbmc_project/inventory/system/chassis/motherboard",
658 "com.ibm.ipzvpd.VSYS");
659 svpdBusData.emplace("VSYS", vsys);
660
661 const auto vcen = getAllDBusProperty<GetAllResultType>(
662 constants::pimIntf,
663 "/xyz/openbmc_project/inventory/system/chassis/motherboard",
664 "com.ibm.ipzvpd.VCEN");
665 svpdBusData.emplace("VCEN", vcen);
666
667 const auto lxr0 = getAllDBusProperty<GetAllResultType>(
668 constants::pimIntf,
669 "/xyz/openbmc_project/inventory/system/chassis/motherboard",
670 "com.ibm.ipzvpd.LXR0");
671 svpdBusData.emplace("LXR0", lxr0);
672
673 const auto util = getAllDBusProperty<GetAllResultType>(
674 constants::pimIntf,
675 "/xyz/openbmc_project/inventory/system/chassis/motherboard",
676 "com.ibm.ipzvpd.UTIL");
677 svpdBusData.emplace("UTIL", util);
Priyanga Ramasamy6d5e7342022-10-14 07:17:25 -0500678}
679
680int VpdTool::fixSystemVPD()
681{
682 std::string outline(191, '=');
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600683 cout << "\nRestorable record-keyword pairs and their data on backup & "
684 "primary.\n\n"
Priyanga Ramasamy6d5e7342022-10-14 07:17:25 -0500685 << outline << std::endl;
686
687 cout << left << setw(6) << "S.No" << left << setw(8) << "Record" << left
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600688 << setw(9) << "Keyword" << left << setw(75) << "Data On Backup" << left
689 << setw(75) << "Data On Primary" << left << setw(14)
Priyanga Ramasamy6d5e7342022-10-14 07:17:25 -0500690 << "Data Mismatch\n"
691 << outline << std::endl;
692
693 int num = 0;
694
695 // Get system VPD data in map
696 unordered_map<string, DbusPropertyMap> vpdMap;
697 json js;
698 getVPDInMap(constants::systemVpdFilePath, vpdMap, js,
699 constants::pimPath +
700 static_cast<std::string>(constants::SYSTEM_OBJECT));
701
702 // Get system VPD D-Bus Data in a map
703 IntfPropMap svpdBusData;
704 getSystemDataFromCache(svpdBusData);
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500705
706 for (const auto& recordKw : svpdKwdMap)
707 {
708 string record = recordKw.first;
709
710 // Extract specific record data from the svpdBusData map.
711 const auto& rec = svpdBusData.find(record);
712
713 if (rec == svpdBusData.end())
714 {
715 std::cerr << record << " not a part of critical system VPD records."
716 << std::endl;
717 continue;
718 }
719
720 const auto& recData = svpdBusData.find(record)->second;
721
722 string busStr{}, hwValStr{};
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500723
Priyanga Ramasamy952d6c52022-11-07 07:20:24 -0600724 for (const auto& keywordInfo : recordKw.second)
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500725 {
Priyanga Ramasamy952d6c52022-11-07 07:20:24 -0600726 const auto& keyword = get<0>(keywordInfo);
Priyanga Ramasamy6d5e7342022-10-14 07:17:25 -0500727 string mismatch = "NO"; // no mismatch
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500728 string hardwareValue{};
729 auto recItr = vpdMap.find(record);
730
731 if (recItr != vpdMap.end())
732 {
733 DbusPropertyMap& kwValMap = recItr->second;
734 auto kwItr = kwValMap.find(keyword);
735 if (kwItr != kwValMap.end())
736 {
737 hardwareValue = kwItr->second;
738 }
739 }
740
Priyanga Ramasamy6d5e7342022-10-14 07:17:25 -0500741 inventory::Value kwValue;
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500742 for (auto& kwData : recData)
743 {
744 if (kwData.first == keyword)
745 {
746 kwValue = kwData.second;
747 break;
748 }
749 }
750
751 if (keyword != "SE")
752 {
753 ostringstream hwValStream;
754 hwValStream << "0x";
755 hwValStr = hwValStream.str();
756
757 for (uint16_t byte : hardwareValue)
758 {
759 hwValStream << setfill('0') << setw(2) << hex << byte;
760 hwValStr = hwValStream.str();
761 }
762
763 if (const auto value = get_if<Binary>(&kwValue))
764 {
765 busStr = byteArrayToHexString(*value);
766 }
767 if (busStr != hwValStr)
768 {
769 mismatch = "YES";
770 }
771 }
772 else
773 {
774 if (const auto value = get_if<Binary>(&kwValue))
775 {
776 busStr = getPrintableValue(*value);
777 }
778 if (busStr != hardwareValue)
779 {
780 mismatch = "YES";
781 }
782 hwValStr = hardwareValue;
783 }
784 recKwData.push_back(
785 make_tuple(++num, record, keyword, busStr, hwValStr, mismatch));
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500786
Priyanga Ramasamy0ac10852022-10-26 05:35:42 -0500787 std::string splitLine(191, '-');
788 cout << left << setw(6) << num << left << setw(8) << record << left
789 << setw(9) << keyword << left << setw(75) << setfill(' ')
790 << busStr << left << setw(75) << setfill(' ') << hwValStr
791 << left << setw(14) << mismatch << '\n'
792 << splitLine << endl;
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500793 }
794 }
795 parseSVPDOptions(js);
796 return 0;
797}
798
799void VpdTool::parseSVPDOptions(const nlohmann::json& json)
800{
801 do
802 {
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600803 printFixSystemVPDOption(VpdTool::BACKUP_DATA_FOR_ALL);
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500804 printFixSystemVPDOption(VpdTool::SYSTEM_BACKPLANE_DATA_FOR_ALL);
805 printFixSystemVPDOption(VpdTool::MORE_OPTIONS);
806 printFixSystemVPDOption(VpdTool::EXIT);
807
808 int option = 0;
809 cin >> option;
Priyanga Ramasamy0ac10852022-10-26 05:35:42 -0500810
811 std::string outline(191, '=');
812 cout << '\n' << outline << endl;
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500813
814 if (json.find("frus") == json.end())
815 {
816 throw runtime_error("Frus not found in json");
817 }
818
819 bool mismatchFound = false;
820
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600821 if (option == VpdTool::BACKUP_DATA_FOR_ALL)
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500822 {
823 for (const auto& data : recKwData)
824 {
825 if (get<5>(data) == "YES")
826 {
827 EditorImpl edit(constants::systemVpdFilePath, json,
828 get<1>(data), get<2>(data));
829 edit.updateKeyword(toBinary(get<3>(data)), 0, true);
830 mismatchFound = true;
831 }
832 }
833
834 if (mismatchFound)
835 {
836 cout << "\nData updated successfully for all mismatching "
837 "record-keyword pairs by choosing their corresponding "
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600838 "data from backup. Exit successfully.\n"
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500839 << endl;
840 }
841 else
842 {
843 cout << "\nNo mismatch found for any of the above mentioned "
844 "record-keyword pair. Exit successfully.\n";
845 }
846
847 exit(0);
848 }
849 else if (option == VpdTool::SYSTEM_BACKPLANE_DATA_FOR_ALL)
850 {
851 for (const auto& data : recKwData)
852 {
853 if (get<5>(data) == "YES")
854 {
855 EditorImpl edit(constants::systemVpdFilePath, json,
856 get<1>(data), get<2>(data));
857 edit.updateKeyword(toBinary(get<4>(data)), 0, true);
858 mismatchFound = true;
859 }
860 }
861
862 if (mismatchFound)
863 {
864 cout << "\nData updated successfully for all mismatching "
865 "record-keyword pairs by choosing their corresponding "
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600866 "data from primary VPD.\n"
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500867 << endl;
868 }
869 else
870 {
871 cout << "\nNo mismatch found for any of the above mentioned "
872 "record-keyword pair. Exit successfully.\n";
873 }
874
875 exit(0);
876 }
877 else if (option == VpdTool::MORE_OPTIONS)
878 {
879 cout << "\nIterate through all restorable record-keyword pairs\n";
880
881 for (const auto& data : recKwData)
882 {
883 do
884 {
Priyanga Ramasamy0ac10852022-10-26 05:35:42 -0500885 cout << '\n' << outline << endl;
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500886
887 cout << left << setw(6) << "S.No" << left << setw(8)
888 << "Record" << left << setw(9) << "Keyword" << left
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600889 << setw(75) << setfill(' ') << "Backup Data" << left
890 << setw(75) << setfill(' ') << "Primary Data" << left
891 << setw(14) << "Data Mismatch" << endl;
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500892
893 cout << left << setw(6) << get<0>(data) << left << setw(8)
894 << get<1>(data) << left << setw(9) << get<2>(data)
Priyanga Ramasamy0ac10852022-10-26 05:35:42 -0500895 << left << setw(75) << setfill(' ') << get<3>(data)
896 << left << setw(75) << setfill(' ') << get<4>(data)
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500897 << left << setw(14) << get<5>(data);
898
Priyanga Ramasamy0ac10852022-10-26 05:35:42 -0500899 cout << '\n' << outline << endl;
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500900
901 if (get<5>(data) == "NO")
902 {
903 cout << "\nNo mismatch found.\n";
904 printFixSystemVPDOption(VpdTool::NEW_VALUE_ON_BOTH);
905 printFixSystemVPDOption(VpdTool::SKIP_CURRENT);
906 printFixSystemVPDOption(VpdTool::EXIT);
907 }
908 else
909 {
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600910 printFixSystemVPDOption(
911 VpdTool::BACKUP_DATA_FOR_CURRENT);
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500912 printFixSystemVPDOption(
913 VpdTool::SYSTEM_BACKPLANE_DATA_FOR_CURRENT);
914 printFixSystemVPDOption(VpdTool::NEW_VALUE_ON_BOTH);
915 printFixSystemVPDOption(VpdTool::SKIP_CURRENT);
916 printFixSystemVPDOption(VpdTool::EXIT);
917 }
918
919 cin >> option;
Priyanga Ramasamy0ac10852022-10-26 05:35:42 -0500920 cout << '\n' << outline << endl;
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500921
922 EditorImpl edit(constants::systemVpdFilePath, json,
923 get<1>(data), get<2>(data));
924
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600925 if (option == VpdTool::BACKUP_DATA_FOR_CURRENT)
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500926 {
927 edit.updateKeyword(toBinary(get<3>(data)), 0, true);
928 cout << "\nData updated successfully.\n";
929 break;
930 }
931 else if (option ==
932 VpdTool::SYSTEM_BACKPLANE_DATA_FOR_CURRENT)
933 {
934 edit.updateKeyword(toBinary(get<4>(data)), 0, true);
935 cout << "\nData updated successfully.\n";
936 break;
937 }
938 else if (option == VpdTool::NEW_VALUE_ON_BOTH)
939 {
940 string value;
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600941 cout << "\nEnter the new value to update on both "
942 "primary & backup. Value should be in ASCII or "
943 "in HEX(prefixed with 0x) : ";
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500944 cin >> value;
Priyanga Ramasamy0ac10852022-10-26 05:35:42 -0500945 cout << '\n' << outline << endl;
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500946
947 edit.updateKeyword(toBinary(value), 0, true);
948 cout << "\nData updated successfully.\n";
949 break;
950 }
951 else if (option == VpdTool::SKIP_CURRENT)
952 {
953 cout << "\nSkipped the above record-keyword pair. "
954 "Continue to the next available pair.\n";
955 break;
956 }
957 else if (option == VpdTool::EXIT)
958 {
959 cout << "\nExit successfully\n";
960 exit(0);
961 }
962 else
963 {
964 cout << "\nProvide a valid option. Retrying for the "
965 "current record-keyword pair\n";
966 }
967 } while (1);
968 }
969 exit(0);
970 }
971 else if (option == VpdTool::EXIT)
972 {
973 cout << "\nExit successfully";
974 exit(0);
975 }
976 else
977 {
978 cout << "\nProvide a valid option. Retry.";
979 continue;
980 }
981
982 } while (true);
Priyanga Ramasamy124ae6c2022-10-18 12:46:14 -0500983}
984
985int VpdTool::cleanSystemVPD()
986{
987 try
988 {
989 // Get system VPD hardware data in map
990 unordered_map<string, DbusPropertyMap> vpdMap;
991 json js;
992 getVPDInMap(constants::systemVpdFilePath, vpdMap, js,
993 constants::pimPath +
994 static_cast<std::string>(constants::SYSTEM_OBJECT));
995
996 RecKwValMap kwdsToBeUpdated;
997
998 for (auto recordMap : svpdKwdMap)
999 {
1000 const auto& record = recordMap.first;
1001 std::unordered_map<std::string, Binary> kwDefault;
1002 for (auto keywordMap : recordMap.second)
1003 {
1004 // Skip those keywords which cannot be reset at manufacturing
1005 if (!std::get<3>(keywordMap))
1006 {
1007 continue;
1008 }
1009 const auto& keyword = std::get<0>(keywordMap);
1010
1011 // Get hardware value for this keyword from vpdMap
1012 Binary hardwareValue;
1013
1014 auto recItr = vpdMap.find(record);
1015
1016 if (recItr != vpdMap.end())
1017 {
1018 DbusPropertyMap& kwValMap = recItr->second;
1019 auto kwItr = kwValMap.find(keyword);
1020 if (kwItr != kwValMap.end())
1021 {
1022 hardwareValue = toBinary(kwItr->second);
1023 }
1024 }
1025
1026 // compare hardware value with the keyword's default value
1027 auto defaultValue = std::get<1>(keywordMap);
1028 if (hardwareValue != defaultValue)
1029 {
1030 EditorImpl edit(constants::systemVpdFilePath, js, record,
1031 keyword);
1032 edit.updateKeyword(defaultValue, 0, true);
1033 }
1034 }
1035 }
1036
1037 std::cout
1038 << "\n The critical keywords from system backplane VPD has been "
1039 "reset successfully."
1040 << std::endl;
1041 }
1042 catch (const std::exception& e)
1043 {
1044 std::cerr << e.what();
1045 std::cerr
1046 << "\nManufacturing reset on system vpd keywords is unsuccessful";
1047 }
1048 return 0;
girik18bb9852022-11-16 05:48:13 -06001049}