blob: 93c4d400567074f54da41e934336a910c4fbc677 [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
Priyanga Ramasamyd90aadb2023-03-28 12:25:14 -0500306json VpdTool::getPresentPropJson(const std::string& invPath)
Priyanga Ramasamy0086dd12021-09-28 10:31:50 -0500307{
308 std::variant<bool> response;
Priyanga Ramasamyd90aadb2023-03-28 12:25:14 -0500309 std::string presence = "Unknown";
Priyanga Ramasamy0086dd12021-09-28 10:31:50 -0500310
Priyanga Ramasamyd90aadb2023-03-28 12:25:14 -0500311 try
Priyanga Ramasamy0086dd12021-09-28 10:31:50 -0500312 {
Priyanga Ramasamyd90aadb2023-03-28 12:25:14 -0500313 makeDBusCall(invPath, "xyz.openbmc_project.Inventory.Item", "Present")
314 .read(response);
315
316 if (auto pVal = get_if<bool>(&response))
Priyanga Ramasamy0086dd12021-09-28 10:31:50 -0500317 {
Priyanga Ramasamyd90aadb2023-03-28 12:25:14 -0500318 presence = *pVal ? "true" : "false";
Priyanga Ramasamy0086dd12021-09-28 10:31:50 -0500319 }
320 }
Priyanga Ramasamyd90aadb2023-03-28 12:25:14 -0500321 catch (const sdbusplus::exception::SdBusError& e)
Priyanga Ramasamy0086dd12021-09-28 10:31:50 -0500322 {
Priyanga Ramasamyd90aadb2023-03-28 12:25:14 -0500323 // not required to handle the exception. Present will be set to Unknown
Priyanga Ramasamy0086dd12021-09-28 10:31:50 -0500324 }
Priyanga Ramasamy0086dd12021-09-28 10:31:50 -0500325 json js;
326 js.emplace("Present", presence);
327 return js;
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530328}
329
330json VpdTool::parseInvJson(const json& jsObject, char flag, string fruPath)
331{
332 json output = json::object({});
333 bool validObject = false;
334
335 if (jsObject.find("frus") == jsObject.end())
336 {
337 throw runtime_error("Frus missing in Inventory json");
338 }
339 else
340 {
341 for (const auto& itemFRUS : jsObject["frus"].items())
342 {
343 for (auto itemEEPROM : itemFRUS.value())
344 {
Priyanga Ramasamy0086dd12021-09-28 10:31:50 -0500345 json subOutput = json::object({});
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530346 try
347 {
348 if (flag == 'O')
349 {
350 if (itemEEPROM.find("inventoryPath") ==
351 itemEEPROM.end())
352 {
353 throw runtime_error("Inventory Path not found");
354 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530355 else if (itemEEPROM.at("inventoryPath") == fruPath)
356 {
357 validObject = true;
Priyanga Ramasamy0086dd12021-09-28 10:31:50 -0500358 subOutput = interfaceDecider(itemEEPROM);
359 json presentJs = getPresentPropJson(
Priyanga Ramasamyd90aadb2023-03-28 12:25:14 -0500360 "/xyz/openbmc_project/inventory" + fruPath);
Priyanga Ramasamy0086dd12021-09-28 10:31:50 -0500361 subOutput.insert(presentJs.begin(),
362 presentJs.end());
363 output.emplace(fruPath, subOutput);
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530364 return output;
365 }
366 }
367 else
368 {
Priyanga Ramasamy0086dd12021-09-28 10:31:50 -0500369 subOutput = interfaceDecider(itemEEPROM);
370 json presentJs = getPresentPropJson(
371 "/xyz/openbmc_project/inventory" +
Priyanga Ramasamyd90aadb2023-03-28 12:25:14 -0500372 string(itemEEPROM.at("inventoryPath")));
Priyanga Ramasamy0086dd12021-09-28 10:31:50 -0500373 subOutput.insert(presentJs.begin(), presentJs.end());
374 output.emplace(string(itemEEPROM.at("inventoryPath")),
375 subOutput);
376 }
377 }
Patrick Williams8e15b932021-10-06 13:04:22 -0500378 catch (const exception& e)
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530379 {
380 cerr << e.what();
381 }
382 }
383 }
384 if ((flag == 'O') && (!validObject))
385 {
386 throw runtime_error(
387 "Invalid object path. Refer --dumpInventory/-i option.");
388 }
389 }
390 return output;
391}
392
393void VpdTool::dumpInventory(const nlohmann::basic_json<>& jsObject)
394{
395 char flag = 'I';
PriyangaRamasamycdf943c2020-03-18 02:25:30 +0530396 json output = json::array({});
397 output.emplace_back(parseInvJson(jsObject, flag, ""));
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530398 debugger(output);
399}
400
401void VpdTool::dumpObject(const nlohmann::basic_json<>& jsObject)
402{
403 char flag = 'O';
PriyangaRamasamycdf943c2020-03-18 02:25:30 +0530404 json output = json::array({});
Santosh Puranikd5d52bb2020-07-28 15:08:10 +0530405 output.emplace_back(parseInvJson(jsObject, flag, fruPath));
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530406 debugger(output);
407}
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530408
409void VpdTool::readKeyword()
410{
411 string interface = "com.ibm.ipzvpd.";
412 variant<Binary> response;
413
414 try
415 {
416 json output = json::object({});
417 json kwVal = json::object({});
418 makeDBusCall(INVENTORY_PATH + fruPath, interface + recordName, keyword)
419 .read(response);
420
PriyangaRamasamy887a42a2020-09-03 00:33:57 +0530421 string printableVal{};
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530422 if (auto vec = get_if<Binary>(&response))
423 {
PriyangaRamasamy887a42a2020-09-03 00:33:57 +0530424 printableVal = getPrintableValue(*vec);
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530425 }
PriyangaRamasamy887a42a2020-09-03 00:33:57 +0530426 kwVal.emplace(keyword, printableVal);
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530427
428 output.emplace(fruPath, kwVal);
429
430 debugger(output);
431 }
Patrick Williams8e15b932021-10-06 13:04:22 -0500432 catch (const json::exception& e)
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530433 {
GiridhariKrishnan63639102023-03-02 05:55:47 -0600434 std::cout << "Keyword Value: " << keyword << std::endl;
435 std::cout << e.what() << std::endl;
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530436 }
437}
PriyangaRamasamyd09d2ec2020-03-12 14:11:50 +0530438
439int VpdTool::updateKeyword()
440{
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +0530441 Binary val = toBinary(value);
PriyangaRamasamyd09d2ec2020-03-12 14:11:50 +0530442 auto bus = sdbusplus::bus::new_default();
443 auto properties =
444 bus.new_method_call(BUSNAME, OBJPATH, IFACE, "WriteKeyword");
445 properties.append(static_cast<sdbusplus::message::object_path>(fruPath));
446 properties.append(recordName);
447 properties.append(keyword);
448 properties.append(val);
449 auto result = bus.call(properties);
450
451 if (result.is_method_error())
452 {
453 throw runtime_error("Get api failed");
454 }
455 return 0;
456}
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530457
458void VpdTool::forceReset(const nlohmann::basic_json<>& jsObject)
459{
460 for (const auto& itemFRUS : jsObject["frus"].items())
461 {
462 for (const auto& itemEEPROM : itemFRUS.value().items())
463 {
464 string fru = itemEEPROM.value().at("inventoryPath");
465
466 fs::path fruCachePath = INVENTORY_MANAGER_CACHE;
467 fruCachePath += INVENTORY_PATH;
468 fruCachePath += fru;
469
470 try
471 {
472 for (const auto& it : fs::directory_iterator(fruCachePath))
473 {
474 if (fs::is_regular_file(it.status()))
475 {
476 fs::remove(it);
477 }
478 }
479 }
480 catch (const fs::filesystem_error& e)
481 {
482 }
483 }
484 }
485
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600486 cout.flush();
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530487 string udevRemove = "udevadm trigger -c remove -s \"*nvmem*\" -v";
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600488 int returnCode = system(udevRemove.c_str());
489 printReturnCode(returnCode);
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530490
491 string invManagerRestart =
492 "systemctl restart xyz.openbmc_project.Inventory.Manager.service";
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600493 returnCode = system(invManagerRestart.c_str());
494 printReturnCode(returnCode);
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530495
Santosh Puranik6c7a84e2022-03-09 13:42:18 +0530496 string sysVpdRestart = "systemctl restart system-vpd.service";
497 returnCode = system(sysVpdRestart.c_str());
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600498 printReturnCode(returnCode);
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530499
500 string udevAdd = "udevadm trigger -c add -s \"*nvmem*\" -v";
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600501 returnCode = system(udevAdd.c_str());
502 printReturnCode(returnCode);
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530503}
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +0530504
Priyanga Ramasamyc99a0b02022-06-08 14:53:39 -0500505int VpdTool::updateHardware(const uint32_t offset)
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +0530506{
507 int rc = 0;
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +0530508 const Binary& val = static_cast<const Binary&>(toBinary(value));
509 ifstream inventoryJson(INVENTORY_JSON_SYM_LINK);
510 try
511 {
512 auto json = nlohmann::json::parse(inventoryJson);
513 EditorImpl edit(fruPath, json, recordName, keyword);
Priyanga Ramasamyc99a0b02022-06-08 14:53:39 -0500514
515 edit.updateKeyword(val, offset, false);
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +0530516 }
Patrick Williams8e15b932021-10-06 13:04:22 -0500517 catch (const json::parse_error& ex)
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +0530518 {
519 throw(VpdJsonException("Json Parsing failed", INVENTORY_JSON_SYM_LINK));
520 }
521 return rc;
Priyanga Ramasamy38031312021-10-07 16:39:13 -0500522}
523
Priyanga Ramasamyc99a0b02022-06-08 14:53:39 -0500524void VpdTool::readKwFromHw(const uint32_t& startOffset)
Priyanga Ramasamy38031312021-10-07 16:39:13 -0500525{
Priyanga Ramasamy38031312021-10-07 16:39:13 -0500526 ifstream inventoryJson(INVENTORY_JSON_SYM_LINK);
527 auto jsonFile = nlohmann::json::parse(inventoryJson);
528
Priyanga Ramasamy38031312021-10-07 16:39:13 -0500529 Binary completeVPDFile;
530 completeVPDFile.resize(65504);
531 fstream vpdFileStream;
532 vpdFileStream.open(fruPath,
533 std::ios::in | std::ios::out | std::ios::binary);
534
535 vpdFileStream.seekg(startOffset, ios_base::cur);
536 vpdFileStream.read(reinterpret_cast<char*>(&completeVPDFile[0]), 65504);
537 completeVPDFile.resize(vpdFileStream.gcount());
538 vpdFileStream.clear(std::ios_base::eofbit);
539
540 if (completeVPDFile.empty())
541 {
542 throw std::runtime_error("Invalid File");
543 }
Sunny Srivastavaf31a91b2022-06-09 08:11:29 -0500544
545 const std::string& inventoryPath =
546 jsonFile["frus"][fruPath][0]["inventoryPath"];
547
girik18bb9852022-11-16 05:48:13 -0600548 uint32_t vpdStartOffset = 0;
549 for (const auto& item : jsonFile["frus"][fruPath])
550 {
551 if (item.find("offset") != item.end())
552 {
553 vpdStartOffset = item["offset"];
554 }
555 }
556
557 Impl obj(completeVPDFile, (constants::pimPath + inventoryPath), fruPath,
558 vpdStartOffset);
Priyanga Ramasamy38031312021-10-07 16:39:13 -0500559 std::string keywordVal = obj.readKwFromHw(recordName, keyword);
560
561 if (!keywordVal.empty())
562 {
563 json output = json::object({});
564 json kwVal = json::object({});
GiridhariKrishnan63639102023-03-02 05:55:47 -0600565 kwVal.emplace(keyword, getPrintableValue(keywordVal));
Priyanga Ramasamy38031312021-10-07 16:39:13 -0500566
567 output.emplace(fruPath, kwVal);
568
569 debugger(output);
570 }
571 else
572 {
573 std::cerr << "The given keyword " << keyword << " or record "
574 << recordName
575 << " or both are not present in the given FRU path "
576 << fruPath << std::endl;
577 }
578}
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500579
580void VpdTool::printFixSystemVPDOption(UserOption option)
581{
582 switch (option)
583 {
584 case VpdTool::EXIT:
585 cout << "\nEnter 0 => To exit successfully : ";
586 break;
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600587 case VpdTool::BACKUP_DATA_FOR_ALL:
588 cout << "\n\nEnter 1 => If you choose the data on backup for all "
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500589 "mismatching record-keyword pairs";
590 break;
591 case VpdTool::SYSTEM_BACKPLANE_DATA_FOR_ALL:
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600592 cout << "\nEnter 2 => If you choose the data on primary for all "
593 "mismatching record-keyword pairs";
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500594 break;
595 case VpdTool::MORE_OPTIONS:
596 cout << "\nEnter 3 => If you wish to explore more options";
597 break;
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600598 case VpdTool::BACKUP_DATA_FOR_CURRENT:
599 cout << "\nEnter 4 => If you choose the data on backup as the "
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500600 "right value";
601 break;
602 case VpdTool::SYSTEM_BACKPLANE_DATA_FOR_CURRENT:
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600603 cout << "\nEnter 5 => If you choose the data on primary as the "
604 "right value";
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500605 break;
606 case VpdTool::NEW_VALUE_ON_BOTH:
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600607 cout << "\nEnter 6 => If you wish to enter a new value to update "
608 "both on backup and primary";
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500609 break;
610 case VpdTool::SKIP_CURRENT:
611 cout << "\nEnter 7 => If you wish to skip the above "
612 "record-keyword pair";
613 break;
614 }
615}
616
Priyanga Ramasamy6d5e7342022-10-14 07:17:25 -0500617void VpdTool::getSystemDataFromCache(IntfPropMap& svpdBusData)
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500618{
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500619 const auto vsys = getAllDBusProperty<GetAllResultType>(
620 constants::pimIntf,
621 "/xyz/openbmc_project/inventory/system/chassis/motherboard",
622 "com.ibm.ipzvpd.VSYS");
623 svpdBusData.emplace("VSYS", vsys);
624
625 const auto vcen = getAllDBusProperty<GetAllResultType>(
626 constants::pimIntf,
627 "/xyz/openbmc_project/inventory/system/chassis/motherboard",
628 "com.ibm.ipzvpd.VCEN");
629 svpdBusData.emplace("VCEN", vcen);
630
631 const auto lxr0 = getAllDBusProperty<GetAllResultType>(
632 constants::pimIntf,
633 "/xyz/openbmc_project/inventory/system/chassis/motherboard",
634 "com.ibm.ipzvpd.LXR0");
635 svpdBusData.emplace("LXR0", lxr0);
636
637 const auto util = getAllDBusProperty<GetAllResultType>(
638 constants::pimIntf,
639 "/xyz/openbmc_project/inventory/system/chassis/motherboard",
640 "com.ibm.ipzvpd.UTIL");
641 svpdBusData.emplace("UTIL", util);
Priyanga Ramasamy6d5e7342022-10-14 07:17:25 -0500642}
643
644int VpdTool::fixSystemVPD()
645{
646 std::string outline(191, '=');
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600647 cout << "\nRestorable record-keyword pairs and their data on backup & "
648 "primary.\n\n"
Priyanga Ramasamy6d5e7342022-10-14 07:17:25 -0500649 << outline << std::endl;
650
651 cout << left << setw(6) << "S.No" << left << setw(8) << "Record" << left
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600652 << setw(9) << "Keyword" << left << setw(75) << "Data On Backup" << left
653 << setw(75) << "Data On Primary" << left << setw(14)
Priyanga Ramasamy6d5e7342022-10-14 07:17:25 -0500654 << "Data Mismatch\n"
655 << outline << std::endl;
656
657 int num = 0;
658
659 // Get system VPD data in map
660 unordered_map<string, DbusPropertyMap> vpdMap;
661 json js;
662 getVPDInMap(constants::systemVpdFilePath, vpdMap, js,
663 constants::pimPath +
664 static_cast<std::string>(constants::SYSTEM_OBJECT));
665
666 // Get system VPD D-Bus Data in a map
667 IntfPropMap svpdBusData;
668 getSystemDataFromCache(svpdBusData);
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500669
670 for (const auto& recordKw : svpdKwdMap)
671 {
672 string record = recordKw.first;
673
674 // Extract specific record data from the svpdBusData map.
675 const auto& rec = svpdBusData.find(record);
676
677 if (rec == svpdBusData.end())
678 {
679 std::cerr << record << " not a part of critical system VPD records."
680 << std::endl;
681 continue;
682 }
683
684 const auto& recData = svpdBusData.find(record)->second;
685
686 string busStr{}, hwValStr{};
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500687
Priyanga Ramasamy952d6c52022-11-07 07:20:24 -0600688 for (const auto& keywordInfo : recordKw.second)
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500689 {
Priyanga Ramasamy952d6c52022-11-07 07:20:24 -0600690 const auto& keyword = get<0>(keywordInfo);
Priyanga Ramasamy6d5e7342022-10-14 07:17:25 -0500691 string mismatch = "NO"; // no mismatch
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500692 string hardwareValue{};
693 auto recItr = vpdMap.find(record);
694
695 if (recItr != vpdMap.end())
696 {
697 DbusPropertyMap& kwValMap = recItr->second;
698 auto kwItr = kwValMap.find(keyword);
699 if (kwItr != kwValMap.end())
700 {
701 hardwareValue = kwItr->second;
702 }
703 }
704
Priyanga Ramasamy6d5e7342022-10-14 07:17:25 -0500705 inventory::Value kwValue;
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500706 for (auto& kwData : recData)
707 {
708 if (kwData.first == keyword)
709 {
710 kwValue = kwData.second;
711 break;
712 }
713 }
714
GiridhariKrishnan63639102023-03-02 05:55:47 -0600715 if (keyword != "SE") // SE to display in Hex string only
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500716 {
717 ostringstream hwValStream;
718 hwValStream << "0x";
719 hwValStr = hwValStream.str();
720
721 for (uint16_t byte : hardwareValue)
722 {
723 hwValStream << setfill('0') << setw(2) << hex << byte;
724 hwValStr = hwValStream.str();
725 }
726
727 if (const auto value = get_if<Binary>(&kwValue))
728 {
GiridhariKrishnan63639102023-03-02 05:55:47 -0600729 busStr = hexString(*value);
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500730 }
731 if (busStr != hwValStr)
732 {
733 mismatch = "YES";
734 }
735 }
736 else
737 {
738 if (const auto value = get_if<Binary>(&kwValue))
739 {
740 busStr = getPrintableValue(*value);
741 }
742 if (busStr != hardwareValue)
743 {
744 mismatch = "YES";
745 }
746 hwValStr = hardwareValue;
747 }
748 recKwData.push_back(
749 make_tuple(++num, record, keyword, busStr, hwValStr, mismatch));
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500750
Priyanga Ramasamy0ac10852022-10-26 05:35:42 -0500751 std::string splitLine(191, '-');
752 cout << left << setw(6) << num << left << setw(8) << record << left
753 << setw(9) << keyword << left << setw(75) << setfill(' ')
754 << busStr << left << setw(75) << setfill(' ') << hwValStr
755 << left << setw(14) << mismatch << '\n'
756 << splitLine << endl;
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500757 }
758 }
759 parseSVPDOptions(js);
760 return 0;
761}
762
763void VpdTool::parseSVPDOptions(const nlohmann::json& json)
764{
765 do
766 {
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600767 printFixSystemVPDOption(VpdTool::BACKUP_DATA_FOR_ALL);
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500768 printFixSystemVPDOption(VpdTool::SYSTEM_BACKPLANE_DATA_FOR_ALL);
769 printFixSystemVPDOption(VpdTool::MORE_OPTIONS);
770 printFixSystemVPDOption(VpdTool::EXIT);
771
772 int option = 0;
773 cin >> option;
Priyanga Ramasamy0ac10852022-10-26 05:35:42 -0500774
775 std::string outline(191, '=');
776 cout << '\n' << outline << endl;
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500777
778 if (json.find("frus") == json.end())
779 {
780 throw runtime_error("Frus not found in json");
781 }
782
783 bool mismatchFound = false;
784
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600785 if (option == VpdTool::BACKUP_DATA_FOR_ALL)
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500786 {
787 for (const auto& data : recKwData)
788 {
789 if (get<5>(data) == "YES")
790 {
791 EditorImpl edit(constants::systemVpdFilePath, json,
792 get<1>(data), get<2>(data));
793 edit.updateKeyword(toBinary(get<3>(data)), 0, true);
794 mismatchFound = true;
795 }
796 }
797
798 if (mismatchFound)
799 {
800 cout << "\nData updated successfully for all mismatching "
801 "record-keyword pairs by choosing their corresponding "
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600802 "data from backup. Exit successfully.\n"
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500803 << endl;
804 }
805 else
806 {
807 cout << "\nNo mismatch found for any of the above mentioned "
808 "record-keyword pair. Exit successfully.\n";
809 }
810
811 exit(0);
812 }
813 else if (option == VpdTool::SYSTEM_BACKPLANE_DATA_FOR_ALL)
814 {
815 for (const auto& data : recKwData)
816 {
817 if (get<5>(data) == "YES")
818 {
819 EditorImpl edit(constants::systemVpdFilePath, json,
820 get<1>(data), get<2>(data));
821 edit.updateKeyword(toBinary(get<4>(data)), 0, true);
822 mismatchFound = true;
823 }
824 }
825
826 if (mismatchFound)
827 {
828 cout << "\nData updated successfully for all mismatching "
829 "record-keyword pairs by choosing their corresponding "
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600830 "data from primary VPD.\n"
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500831 << endl;
832 }
833 else
834 {
835 cout << "\nNo mismatch found for any of the above mentioned "
836 "record-keyword pair. Exit successfully.\n";
837 }
838
839 exit(0);
840 }
841 else if (option == VpdTool::MORE_OPTIONS)
842 {
843 cout << "\nIterate through all restorable record-keyword pairs\n";
844
845 for (const auto& data : recKwData)
846 {
847 do
848 {
Priyanga Ramasamy0ac10852022-10-26 05:35:42 -0500849 cout << '\n' << outline << endl;
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500850
851 cout << left << setw(6) << "S.No" << left << setw(8)
852 << "Record" << left << setw(9) << "Keyword" << left
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600853 << setw(75) << setfill(' ') << "Backup Data" << left
854 << setw(75) << setfill(' ') << "Primary Data" << left
855 << setw(14) << "Data Mismatch" << endl;
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500856
857 cout << left << setw(6) << get<0>(data) << left << setw(8)
858 << get<1>(data) << left << setw(9) << get<2>(data)
Priyanga Ramasamy0ac10852022-10-26 05:35:42 -0500859 << left << setw(75) << setfill(' ') << get<3>(data)
860 << left << setw(75) << setfill(' ') << get<4>(data)
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500861 << left << setw(14) << get<5>(data);
862
Priyanga Ramasamy0ac10852022-10-26 05:35:42 -0500863 cout << '\n' << outline << endl;
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500864
865 if (get<5>(data) == "NO")
866 {
867 cout << "\nNo mismatch found.\n";
868 printFixSystemVPDOption(VpdTool::NEW_VALUE_ON_BOTH);
869 printFixSystemVPDOption(VpdTool::SKIP_CURRENT);
870 printFixSystemVPDOption(VpdTool::EXIT);
871 }
872 else
873 {
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600874 printFixSystemVPDOption(
875 VpdTool::BACKUP_DATA_FOR_CURRENT);
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500876 printFixSystemVPDOption(
877 VpdTool::SYSTEM_BACKPLANE_DATA_FOR_CURRENT);
878 printFixSystemVPDOption(VpdTool::NEW_VALUE_ON_BOTH);
879 printFixSystemVPDOption(VpdTool::SKIP_CURRENT);
880 printFixSystemVPDOption(VpdTool::EXIT);
881 }
882
883 cin >> option;
Priyanga Ramasamy0ac10852022-10-26 05:35:42 -0500884 cout << '\n' << outline << endl;
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500885
886 EditorImpl edit(constants::systemVpdFilePath, json,
887 get<1>(data), get<2>(data));
888
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600889 if (option == VpdTool::BACKUP_DATA_FOR_CURRENT)
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500890 {
891 edit.updateKeyword(toBinary(get<3>(data)), 0, true);
892 cout << "\nData updated successfully.\n";
893 break;
894 }
895 else if (option ==
896 VpdTool::SYSTEM_BACKPLANE_DATA_FOR_CURRENT)
897 {
898 edit.updateKeyword(toBinary(get<4>(data)), 0, true);
899 cout << "\nData updated successfully.\n";
900 break;
901 }
902 else if (option == VpdTool::NEW_VALUE_ON_BOTH)
903 {
904 string value;
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600905 cout << "\nEnter the new value to update on both "
906 "primary & backup. Value should be in ASCII or "
907 "in HEX(prefixed with 0x) : ";
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500908 cin >> value;
Priyanga Ramasamy0ac10852022-10-26 05:35:42 -0500909 cout << '\n' << outline << endl;
Priyanga Ramasamy43ffcf72022-06-08 14:10:11 -0500910
911 edit.updateKeyword(toBinary(value), 0, true);
912 cout << "\nData updated successfully.\n";
913 break;
914 }
915 else if (option == VpdTool::SKIP_CURRENT)
916 {
917 cout << "\nSkipped the above record-keyword pair. "
918 "Continue to the next available pair.\n";
919 break;
920 }
921 else if (option == VpdTool::EXIT)
922 {
923 cout << "\nExit successfully\n";
924 exit(0);
925 }
926 else
927 {
928 cout << "\nProvide a valid option. Retrying for the "
929 "current record-keyword pair\n";
930 }
931 } while (1);
932 }
933 exit(0);
934 }
935 else if (option == VpdTool::EXIT)
936 {
937 cout << "\nExit successfully";
938 exit(0);
939 }
940 else
941 {
942 cout << "\nProvide a valid option. Retry.";
943 continue;
944 }
945
946 } while (true);
Priyanga Ramasamy124ae6c2022-10-18 12:46:14 -0500947}
948
949int VpdTool::cleanSystemVPD()
950{
951 try
952 {
953 // Get system VPD hardware data in map
954 unordered_map<string, DbusPropertyMap> vpdMap;
955 json js;
956 getVPDInMap(constants::systemVpdFilePath, vpdMap, js,
957 constants::pimPath +
958 static_cast<std::string>(constants::SYSTEM_OBJECT));
959
960 RecKwValMap kwdsToBeUpdated;
961
962 for (auto recordMap : svpdKwdMap)
963 {
964 const auto& record = recordMap.first;
965 std::unordered_map<std::string, Binary> kwDefault;
966 for (auto keywordMap : recordMap.second)
967 {
968 // Skip those keywords which cannot be reset at manufacturing
969 if (!std::get<3>(keywordMap))
970 {
971 continue;
972 }
973 const auto& keyword = std::get<0>(keywordMap);
974
975 // Get hardware value for this keyword from vpdMap
976 Binary hardwareValue;
977
978 auto recItr = vpdMap.find(record);
979
980 if (recItr != vpdMap.end())
981 {
982 DbusPropertyMap& kwValMap = recItr->second;
983 auto kwItr = kwValMap.find(keyword);
984 if (kwItr != kwValMap.end())
985 {
986 hardwareValue = toBinary(kwItr->second);
987 }
988 }
989
990 // compare hardware value with the keyword's default value
991 auto defaultValue = std::get<1>(keywordMap);
992 if (hardwareValue != defaultValue)
993 {
994 EditorImpl edit(constants::systemVpdFilePath, js, record,
995 keyword);
996 edit.updateKeyword(defaultValue, 0, true);
997 }
998 }
999 }
1000
1001 std::cout
1002 << "\n The critical keywords from system backplane VPD has been "
1003 "reset successfully."
1004 << std::endl;
1005 }
1006 catch (const std::exception& e)
1007 {
1008 std::cerr << e.what();
1009 std::cerr
1010 << "\nManufacturing reset on system vpd keywords is unsuccessful";
1011 }
1012 return 0;
girik18bb9852022-11-16 05:48:13 -06001013}