1 #pragma once
2
3 #include "const.hpp"
4 #include "store.hpp"
5 #include "types.hpp"
6
7 #include <nlohmann/json.hpp>
8
9 #include <iostream>
10 #include <optional>
11 #include <variant>
12
13 namespace openpower
14 {
15 namespace vpd
16 {
17
18 // Map which holds system vpd keywords which can be restored at standby and via
19 // vpd-tool and also can be used to reset keywords to its defaults at
20 // manufacturing. The list of keywords for VSYS record is as per the S0 system.
21 // Should be updated for another type of systems For those keywords whose
22 // default value is system specific, the default value field is left empty.
23 // Record : {Keyword, Default value, Is PEL required on restore failure, Is MFG
24 // reset required, backupVpdRecName, backupVpdKwName}
25 static const inventory::SystemKeywordsMap svpdKwdMap{
26 {"VSYS",
27 {inventory::SystemKeywordInfo("BR", Binary(2, 0x20), true, true, "VSBK",
28 "BR"),
29 inventory::SystemKeywordInfo("TM", Binary(8, 0x20), true, true, "VSBK",
30 "TM"),
31 inventory::SystemKeywordInfo("SE", Binary(7, 0x20), true, true, "VSBK",
32 "SE"),
33 inventory::SystemKeywordInfo("SU", Binary(6, 0x20), true, true, "VSBK",
34 "SU"),
35 inventory::SystemKeywordInfo("RB", Binary(4, 0x20), true, true, "VSBK",
36 "RB"),
37 inventory::SystemKeywordInfo("WN", Binary(12, 0x20), true, true, "VSBK",
38 "WN"),
39 inventory::SystemKeywordInfo("RG", Binary(4, 0x20), true, true, "VSBK",
40 "RG"),
41 inventory::SystemKeywordInfo("FV", Binary(32, 0x20), false, true, "VSBK",
42 "FV")}},
43 {"VCEN",
44 {inventory::SystemKeywordInfo("FC", Binary(8, 0x20), true, false, "VSBK",
45 "FC"),
46 inventory::SystemKeywordInfo("SE", Binary(7, 0x20), true, true, "VSBK",
47 "ES")}},
48 {"LXR0",
49 {inventory::SystemKeywordInfo("LX", Binary(8, 0x00), true, false, "VSBK",
50 "LX")}},
51 {"UTIL",
52 {inventory::SystemKeywordInfo("D0", Binary(1, 0x00), true, true, "VSBK",
53 "D0"),
54 inventory::SystemKeywordInfo("D1", Binary(1, 0x00), false, true, "VSBK",
55 "D1"),
56 inventory::SystemKeywordInfo("F0", Binary(8, 0x00), false, true, "VSBK",
57 "F0"),
58 inventory::SystemKeywordInfo("F5", Binary(16, 0x00), false, true, "VSBK",
59 "F5"),
60 inventory::SystemKeywordInfo("F6", Binary(16, 0x00), false, true, "VSBK",
61 "F6")}}};
62
63 /** @brief Return the hex representation of the incoming byte
64 *
65 * @param [in] c - The input byte
66 * @returns The hex representation of the byte as a character.
67 */
toHex(size_t c)68 constexpr auto toHex(size_t c)
69 {
70 constexpr auto map = "0123456789abcdef";
71 return map[c];
72 }
73
74 namespace inventory
75 {
76 /** @brief API to obtain a dictionary of path -> services
77 * where path is in subtree and services is of the type
78 * returned by the GetObject method.
79 *
80 * @param [in] root - Root path for object subtree
81 * @param [in] depth - Maximum subtree depth required
82 * @param [in] interfaces - Array to interfaces for which
83 * result is required.
84 * @return A dictionary of Path -> services
85 */
86 MapperResponse
87 getObjectSubtreeForInterfaces(const std::string& root, const int32_t depth,
88 const std::vector<std::string>& interfaces);
89
90 /**
91 * @brief API to call GetObject API of mapper.
92 *
93 * @param[in] objectPath - inventory path.
94 * @param[in] interfaces - List of interfaces.
95 *
96 * @return - response of the API call.
97 */
98 MapperGetObjectResponse getObject(const std::string& objectPath,
99 const std::vector<std::string>& interfaces);
100
101 } // namespace inventory
102
103 /**@brief This API reads 2 Bytes of data and swap the read data
104 * @param[in] iterator- Pointer pointing to the data to be read
105 * @return returns 2 Byte data read at the given pointer
106 */
107 openpower::vpd::constants::LE2ByteData
108 readUInt16LE(Binary::const_iterator iterator);
109
110 /** @brief Encodes a keyword for D-Bus.
111 * @param[in] kw - kwd data in string format
112 * @param[in] encoding - required for kwd data
113 */
114 std::string encodeKeyword(const std::string& kw, const std::string& encoding);
115
116 /** @brief Reads a property from the inventory manager given object path,
117 * interface and property.
118 * @param[in] obj - object path
119 * @param[in] inf - interface
120 * @param[in] prop - property whose value is fetched
121 * @return [out] - value of the property
122 */
123 std::string readBusProperty(const std::string& obj, const std::string& inf,
124 const std::string& prop);
125
126 /** @brief A templated function to read D-Bus properties.
127 *
128 * @param[in] service - Service path
129 * @param[in] object - object path
130 * @param[in] inf - interface
131 * @param[in] prop - property whose value is fetched
132 * @return The property value of its own type.
133 */
134 template <typename T>
readDBusProperty(const std::string & service,const std::string & object,const std::string & inf,const std::string & prop)135 T readDBusProperty(const std::string& service, const std::string& object,
136 const std::string& inf, const std::string& prop)
137 {
138 T retVal{};
139 try
140 {
141 auto bus = sdbusplus::bus::new_default();
142 auto properties =
143 bus.new_method_call(service.c_str(), object.c_str(),
144 "org.freedesktop.DBus.Properties", "Get");
145 properties.append(inf);
146 properties.append(prop);
147 auto result = bus.call(properties);
148 result.read(retVal);
149 }
150 catch (const sdbusplus::exception::SdBusError& e)
151 {
152 std::cerr << e.what();
153 }
154 return retVal;
155 }
156
157 /** @brief A templated method to get all D-Bus properties
158 *
159 * @param[in] service - Service path
160 * @param[in] object - Object path
161 * @param[in] inf - Interface
162 *
163 * @return All properties under the given interface.
164 */
165 template <typename T>
getAllDBusProperty(const std::string & service,const std::string & object,const std::string & inf)166 T getAllDBusProperty(const std::string& service, const std::string& object,
167 const std::string& inf)
168 {
169 T retVal{};
170 try
171 {
172 auto bus = sdbusplus::bus::new_default();
173 auto allProperties =
174 bus.new_method_call(service.c_str(), object.c_str(),
175 "org.freedesktop.DBus.Properties", "GetAll");
176 allProperties.append(inf);
177
178 auto result = bus.call(allProperties);
179 result.read(retVal);
180 }
181 catch (const sdbusplus::exception::SdBusError& e)
182 {
183 std::cerr << e.what();
184 }
185 return retVal;
186 }
187
188 /**
189 * @brief API to create PEL entry
190 * The api makes synchronous call to phosphor-logging create api.
191 * @param[in] additionalData - Map holding the additional data
192 * @param[in] sev - Severity
193 * @param[in] errIntf - error interface
194 */
195 void createSyncPEL(const std::map<std::string, std::string>& additionalData,
196 const constants::PelSeverity& sev,
197 const std::string& errIntf);
198
199 /**
200 * @brief Api to create PEL.
201 * A wrapper api through which sync/async call to phosphor-logging create api
202 * can be made as and when required.
203 * sdBus as nullptr will result in sync call else async call will be made with
204 * just "DESCRIPTION" key/value pair in additional data.
205 * To make asyn call with more fields in additional data call
206 * "sd_bus_call_method_async" in place.
207 *
208 * @param[in] additionalData - Map of additional data.
209 * @param[in] sev - severity of the PEL.
210 * @param[in] errIntf - Error interface to be used in PEL.
211 * @param[in] sdBus - Pointer to Sd-Bus
212 */
213 void createPEL(const std::map<std::string, std::string>& additionalData,
214 const constants::PelSeverity& sev, const std::string& errIntf,
215 sd_bus* sdBus);
216
217 /**
218 * @brief getVpdFilePath
219 * Get vpd file path corresponding to the given object path.
220 * @param[in] - json file path
221 * @param[in] - Object path
222 * @return - Vpd file path
223 */
224 inventory::VPDfilepath getVpdFilePath(const std::string& jsonFile,
225 const std::string& ObjPath);
226
227 /**
228 * @brief isPathInJson
229 * API which checks for the presence of the given eeprom path in the given json.
230 * @param[in] - eepromPath
231 * @return - true if the eeprom is present in the json; false otherwise
232 */
233 bool isPathInJson(const std::string& eepromPath);
234
235 /**
236 * @brief isRecKwInDbusJson
237 * API which checks whether the given keyword under the given record is to be
238 * published on dbus or not. Checks against the keywords present in
239 * dbus_property.json.
240 * @param[in] - record name
241 * @param[in] - keyword name
242 * @return - true if the record-keyword pair is present in dbus_property.json;
243 * false otherwise.
244 */
245 bool isRecKwInDbusJson(const std::string& record, const std::string& keyword);
246
247 /**
248 * @brief Check the type of VPD.
249 *
250 * Checks the type of vpd based on the start tag.
251 * @param[in] vector - Vpd data in vector format
252 *
253 * @return enum of type vpdType
254 */
255 constants::vpdType vpdTypeCheck(const Binary& vector);
256
257 /*
258 * @brief This method does nothing. Just an empty function to return null
259 * at the end of variadic template args
260 */
getCommand()261 inline std::string getCommand()
262 {
263 return "";
264 }
265
266 /**
267 * @brief This function to arrange all arguments to make commandy
268 * @param[in] arguments to create the command
269 * @return cmd - command string
270 */
271 template <typename T, typename... Types>
getCommand(T arg1,Types...args)272 inline std::string getCommand(T arg1, Types... args)
273 {
274 std::string cmd = " " + arg1 + getCommand(args...);
275
276 return cmd;
277 }
278
279 /**
280 * @brief This API takes arguments, creates a shell command line and executes
281 * them.
282 * @param[in] arguments for command
283 * @returns output of that command
284 */
285 template <typename T, typename... Types>
executeCmd(T && path,Types...args)286 inline std::vector<std::string> executeCmd(T&& path, Types... args)
287 {
288 std::vector<std::string> stdOutput;
289 std::array<char, 128> buffer;
290
291 std::string cmd = path + getCommand(args...);
292
293 struct custom_file_deleter
294 {
295 void operator()(std::FILE* fp)
296 {
297 pclose(fp);
298 }
299 };
300 using unique_file_custom_deleter =
301 std::unique_ptr<std::FILE, custom_file_deleter>;
302 unique_file_custom_deleter pipe{popen(cmd.c_str(), "r")};
303
304 if (!pipe)
305 {
306 throw std::runtime_error("popen() failed!");
307 }
308 while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr)
309 {
310 stdOutput.emplace_back(buffer.data());
311 }
312
313 return stdOutput;
314 }
315
316 /** @brief This API checks for IM and HW keywords, and based
317 * on these values decides which system json to be used.
318 * @param[in] vpdMap - parsed vpd
319 * @returns System json path
320 */
321 std::string getSystemsJson(const Parsed& vpdMap);
322
323 /** @brief Reads HW Keyword from the vpd
324 * @param[in] vpdMap - parsed vpd
325 * @returns value of HW Keyword
326 */
327 const std::string getHW(const Parsed& vpdMap);
328
329 /** @brief Reads IM Keyword from the vpd
330 * @param[in] vpdMap - parsed vpd
331 * @returns value of IM Keyword
332 */
333 const std::string getIM(const Parsed& vpdMap);
334
335 /** @brief Translate udev event generated path to a generic /sys/bus eeprom path
336 * @param[io] file - path generated from udev event.
337 * @param[in] driver - kernel driver used by the device.
338 */
339 void udevToGenericPath(std::string& file, const std::string& driver);
340
341 /**
342 * @brief API to generate a vpd name in some pattern.
343 * This vpd-name denotes name of the bad vpd file.
344 * For i2c eeproms - the pattern of the vpd-name will be
345 * i2c-<bus-number>-<eeprom-address>. For spi eeproms - the pattern of the
346 * vpd-name will be spi-<spi-number>.
347 *
348 * @param[in] file - file path of the vpd
349 * @return the vpd-name.
350 */
351 std::string getBadVpdName(const std::string& file);
352
353 /**
354 * @brief API which dumps the broken/bad vpd in a directory
355 * When the vpd is bad, this api places the bad vpd file inside
356 * "/tmp/bad-vpd" in BMC, in order to collect bad VPD data as a part of user
357 * initiated BMC dump.
358 *
359 * @param[in] file - bad vpd file path
360 * @param[in] vpdVector - bad vpd vector
361 */
362 void dumpBadVpd(const std::string& file, const Binary& vpdVector);
363
364 /*
365 * @brief This function fetches the value for given keyword in the given record
366 * from vpd data and returns this value.
367 *
368 * @param[in] vpdMap - vpd to find out the data
369 * @param[in] rec - Record under which desired keyword exists
370 * @param[in] kwd - keyword to read the data from
371 *
372 * @returns keyword value if record/keyword combination found
373 * empty string if record or keyword is not found.
374 */
375 const std::string getKwVal(const Parsed& vpdMap, const std::string& rec,
376 const std::string& kwd);
377
378 /** @brief This creates a complete command using all it's input parameters,
379 * to bind or unbind the driver.
380 * @param[in] devNameAddr - device address on that bus
381 * @param[in] busType - i2c, spi
382 * @param[in] driverType - type of driver like at24
383 * @param[in] bindOrUnbind - either bind or unbind
384 * @returns Command to bind or unbind the driver.
385 */
createBindUnbindDriverCmnd(const std::string & devNameAddr,const std::string & busType,const std::string & driverType,const std::string & bindOrUnbind)386 inline std::string createBindUnbindDriverCmnd(
387 const std::string& devNameAddr, const std::string& busType,
388 const std::string& driverType, const std::string& bindOrUnbind)
389 {
390 return ("echo " + devNameAddr + " > /sys/bus/" + busType + "/drivers/" +
391 driverType + "/" + bindOrUnbind);
392 }
393
394 /**
395 * @brief Get Printable Value
396 *
397 * Checks if the value has non printable characters.
398 * Returns hex value if non printable char is found else
399 * returns ascii value.
400 *
401 * @param[in] kwVal - Reference of the input data, Keyword value
402 * @return printable value - either in hex or in ascii.
403 */
404 std::string getPrintableValue(const std::variant<Binary, std::string>& kwVal);
405
406 /**
407 * @brief Convert array to hex string.
408 * @param[in] kwVal - input data, Keyword value
409 * @return hexadecimal string of bytes.
410 */
411 std::string hexString(const std::variant<Binary, std::string>& kwVal);
412
413 /**
414 * @brief Return presence of the FRU.
415 *
416 * This API returns the presence information of the FRU corresponding to the
417 * given EEPROM. If the JSON contains no information about presence detect, this
418 * will return an empty optional. Else it will get the presence GPIO information
419 * from the JSON and return the appropriate present status.
420 * In case of GPIO find/read errors, it will return false.
421 *
422 * @param[in] json - The VPD JSON
423 * @param[in] file - EEPROM file path
424 * @return Empty optional if there is no presence info. Else returns presence
425 * based on the GPIO read.
426 */
427 std::optional<bool> isPresent(const nlohmann::json& json,
428 const std::string& file);
429
430 /**
431 * @brief Performs any pre-action needed to get the FRU setup for
432 * collection.
433 *
434 * @param[in] json - json object
435 * @param[in] file - eeprom file path
436 * @return - success or failure
437 */
438 bool executePreAction(const nlohmann::json& json, const std::string& file);
439
440 /**
441 * @brief This API will be called at the end of VPD collection to perform any
442 * post actions.
443 *
444 * @param[in] json - json object
445 * @param[in] file - eeprom file path
446 */
447 void executePostFailAction(const nlohmann::json& json, const std::string& file);
448
449 /**
450 * @brief Helper function to insert or merge in map.
451 *
452 * This method checks in the given inventory::InterfaceMap if the given
453 * interface key is existing or not. If the interface key already exists, given
454 * property map is inserted into it. If the key doesn't exist then given
455 * interface and property map pair is newly created. If the property present in
456 * propertymap already exist in the InterfaceMap, then the new property value is
457 * ignored.
458 *
459 * @param[in,out] map - map object of type inventory::InterfaceMap only.
460 * @param[in] interface - Interface name.
461 * @param[in] property - new property map that needs to be emplaced.
462 */
463 void insertOrMerge(inventory::InterfaceMap& map,
464 const inventory::Interface& interface,
465 inventory::PropertyMap&& property);
466
467 /**
468 * @brief Utility API to set a D-Bus property
469 *
470 * This calls org.freedesktop.DBus.Properties;Set method with the supplied
471 * arguments
472 *
473 * @tparam T Template type of the D-Bus property
474 * @param service[in] - The D-Bus service name.
475 * @param object[in] - The D-Bus object on which the property is to be set.
476 * @param interface[in] - The D-Bus interface to which the property belongs.
477 * @param propertyName[in] - The name of the property to set.
478 * @param propertyValue[in] - The value of the property.
479 */
480 template <typename T>
setBusProperty(const std::string & service,const std::string & object,const std::string & interface,const std::string & propertyName,const std::variant<T> & propertyValue)481 void setBusProperty(const std::string& service, const std::string& object,
482 const std::string& interface,
483 const std::string& propertyName,
484 const std::variant<T>& propertyValue)
485 {
486 try
487 {
488 auto bus = sdbusplus::bus::new_default();
489 auto method =
490 bus.new_method_call(service.c_str(), object.c_str(),
491 "org.freedesktop.DBus.Properties", "Set");
492 method.append(interface);
493 method.append(propertyName);
494 method.append(propertyValue);
495
496 bus.call(method);
497 }
498 catch (const sdbusplus::exception::SdBusError& e)
499 {
500 std::cerr << e.what() << std::endl;
501 }
502 }
503
504 /**
505 * @brief Reads BIOS Attribute by name.
506 *
507 * @param attrName[in] - The BIOS attribute name.
508 * @return std::variant<int64_t, std::string> - The BIOS attribute value.
509 */
510 std::variant<int64_t, std::string>
511 readBIOSAttribute(const std::string& attrName);
512
513 /**
514 * @brief Returns the power state for chassis0
515 * @return The chassis power state.
516 */
517 std::string getPowerState();
518
519 /**
520 * @brief Reads VPD from the supplied EEPROM
521 *
522 * This function reads the given VPD EEPROM file and returns its contents as a
523 * byte array. It handles any offsets into the file that need to be taken care
524 * of by looking up the VPD JSON for a possible offset key.
525 *
526 * @param js[in] - The VPD JSON Object
527 * @param file[in] - The path to the EEPROM to read
528 * @return A byte array containing the raw VPD.
529 */
530 Binary getVpdDataInVector(const nlohmann::json& js, const std::string& file);
531
532 /**
533 * @brief Get D-bus name for the keyword
534 * Some of the VPD keywords has different name in PIM when compared with its
535 * name from hardware. This method returns the D-bus name for the given keyword.
536 *
537 * @param[in] keyword - Keyword name
538 * @return D-bus name for the keyword
539 */
540 std::string getDbusNameForThisKw(const std::string& keyword);
541
542 /**
543 * @brief API to remove VPD data from Dbus on removal of FRU.
544 *
545 * @param[in] objPath - Inventory path of the FRU.
546 * @param[out] interfacesPropMap - Map of interface, property and value.
547 */
548 void clearVpdOnRemoval(const std::string& objPath,
549 inventory::InterfaceMap& interfacesPropMap);
550
551 /**
552 * @brief Find backup VPD path if any for the system VPD
553 *
554 * @param[out] backupEepromPath - Backup VPD path
555 * @param[out] backupInvPath - Backup inventory path
556 * @param[in] js - Inventory JSON object
557 */
558 void findBackupVPDPaths(std::string& backupEepromPath,
559 std::string& backupInvPath, const nlohmann::json& js);
560
561 /**
562 * @brief Get backup VPD's record and keyword for the given system VPD keyword
563 *
564 * @param[in,out] record - Record name
565 * @param[in,out] keyword - Keyword name
566 */
567 void getBackupRecordKeyword(std::string& record, std::string& keyword);
568
569 /**
570 * @brief Check if EEPROM of the given VPD path is read only.
571 *
572 * @param[in] vpdPath - VPD path of the FRU.
573 * @param[in] jsObject - Inventory JSON object.
574 *
575 * @return true if EEPROM is read only, false otherwise.
576 */
577 bool isReadOnlyEEPROM(const std::string& vpdPath,
578 const nlohmann::json& jsObject);
579 } // namespace vpd
580 } // namespace openpower
581