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  */
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>
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 = bus.new_method_call(service.c_str(), object.c_str(),
143                                               "org.freedesktop.DBus.Properties",
144                                               "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>
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  */
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>
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>
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  */
386 inline std::string createBindUnbindDriverCmnd(const std::string& devNameAddr,
387                                               const std::string& busType,
388                                               const std::string& driverType,
389                                               const std::string& bindOrUnbind)
390 {
391     return ("echo " + devNameAddr + " > /sys/bus/" + busType + "/drivers/" +
392             driverType + "/" + bindOrUnbind);
393 }
394 
395 /**
396  * @brief Get Printable Value
397  *
398  * Checks if the value has non printable characters.
399  * Returns hex value if non printable char is found else
400  * returns ascii value.
401  *
402  * @param[in] kwVal - Reference of the input data, Keyword value
403  * @return printable value - either in hex or in ascii.
404  */
405 std::string getPrintableValue(const std::variant<Binary, std::string>& kwVal);
406 
407 /**
408  * @brief Convert array to hex string.
409  * @param[in] kwVal - input data, Keyword value
410  * @return hexadecimal string of bytes.
411  */
412 std::string hexString(const std::variant<Binary, std::string>& kwVal);
413 
414 /**
415  * @brief Return presence of the FRU.
416  *
417  * This API returns the presence information of the FRU corresponding to the
418  * given EEPROM. If the JSON contains no information about presence detect, this
419  * will return an empty optional. Else it will get the presence GPIO information
420  * from the JSON and return the appropriate present status.
421  * In case of GPIO find/read errors, it will return false.
422  *
423  * @param[in] json - The VPD JSON
424  * @param[in] file - EEPROM file path
425  * @return Empty optional if there is no presence info. Else returns presence
426  * based on the GPIO read.
427  */
428 std::optional<bool> isPresent(const nlohmann::json& json,
429                               const std::string& file);
430 
431 /**
432  * @brief Performs any pre-action needed to get the FRU setup for
433  * collection.
434  *
435  * @param[in] json - json object
436  * @param[in] file - eeprom file path
437  * @return - success or failure
438  */
439 bool executePreAction(const nlohmann::json& json, const std::string& file);
440 
441 /**
442  * @brief This API will be called at the end of VPD collection to perform any
443  * post actions.
444  *
445  * @param[in] json - json object
446  * @param[in] file - eeprom file path
447  */
448 void executePostFailAction(const nlohmann::json& json, const std::string& file);
449 
450 /**
451  * @brief Helper function to insert or merge in map.
452  *
453  * This method checks in the given inventory::InterfaceMap if the given
454  * interface key is existing or not. If the interface key already exists, given
455  * property map is inserted into it. If the key doesn't exist then given
456  * interface and property map pair is newly created. If the property present in
457  * propertymap already exist in the InterfaceMap, then the new property value is
458  * ignored.
459  *
460  * @param[in,out] map - map object of type inventory::InterfaceMap only.
461  * @param[in] interface - Interface name.
462  * @param[in] property - new property map that needs to be emplaced.
463  */
464 void insertOrMerge(inventory::InterfaceMap& map,
465                    const inventory::Interface& interface,
466                    inventory::PropertyMap&& property);
467 
468 /**
469  * @brief Utility API to set a D-Bus property
470  *
471  * This calls org.freedesktop.DBus.Properties;Set method with the supplied
472  * arguments
473  *
474  * @tparam T Template type of the D-Bus property
475  * @param service[in] - The D-Bus service name.
476  * @param object[in] - The D-Bus object on which the property is to be set.
477  * @param interface[in] - The D-Bus interface to which the property belongs.
478  * @param propertyName[in] - The name of the property to set.
479  * @param propertyValue[in] - The value of the property.
480  */
481 template <typename T>
482 void setBusProperty(const std::string& service, const std::string& object,
483                     const std::string& interface,
484                     const std::string& propertyName,
485                     const std::variant<T>& propertyValue)
486 {
487     try
488     {
489         auto bus = sdbusplus::bus::new_default();
490         auto method = bus.new_method_call(service.c_str(), object.c_str(),
491                                           "org.freedesktop.DBus.Properties",
492                                           "Set");
493         method.append(interface);
494         method.append(propertyName);
495         method.append(propertyValue);
496 
497         bus.call(method);
498     }
499     catch (const sdbusplus::exception::SdBusError& e)
500     {
501         std::cerr << e.what() << std::endl;
502     }
503 }
504 
505 /**
506  * @brief Reads BIOS Attribute by name.
507  *
508  * @param attrName[in] - The BIOS attribute name.
509  * @return std::variant<int64_t, std::string> - The BIOS attribute value.
510  */
511 std::variant<int64_t, std::string>
512     readBIOSAttribute(const std::string& attrName);
513 
514 /**
515  * @brief Returns the power state for chassis0
516  * @return The chassis power state.
517  */
518 std::string getPowerState();
519 
520 /**
521  * @brief Reads VPD from the supplied EEPROM
522  *
523  * This function reads the given VPD EEPROM file and returns its contents as a
524  * byte array. It handles any offsets into the file that need to be taken care
525  * of by looking up the VPD JSON for a possible offset key.
526  *
527  * @param js[in] - The VPD JSON Object
528  * @param file[in] - The path to the EEPROM to read
529  * @return A byte array containing the raw VPD.
530  */
531 Binary getVpdDataInVector(const nlohmann::json& js, const std::string& file);
532 
533 /**
534  * @brief Get D-bus name for the keyword
535  * Some of the VPD keywords has different name in PIM when compared with its
536  * name from hardware. This method returns the D-bus name for the given keyword.
537  *
538  * @param[in] keyword - Keyword name
539  * @return D-bus name for the keyword
540  */
541 std::string getDbusNameForThisKw(const std::string& keyword);
542 
543 /**
544  * @brief API to remove VPD data from Dbus on removal of FRU.
545  *
546  * @param[in] objPath - Inventory path of the FRU.
547  * @param[out] interfacesPropMap - Map of interface, property and value.
548  */
549 void clearVpdOnRemoval(const std::string& objPath,
550                        inventory::InterfaceMap& interfacesPropMap);
551 
552 /**
553  * @brief Find backup VPD path if any for the system VPD
554  *
555  * @param[out] backupEepromPath - Backup VPD path
556  * @param[out] backupInvPath - Backup inventory path
557  * @param[in] js - Inventory JSON object
558  */
559 void findBackupVPDPaths(std::string& backupEepromPath,
560                         std::string& backupInvPath, const nlohmann::json& js);
561 
562 /**
563  * @brief Get backup VPD's record and keyword for the given system VPD keyword
564  *
565  * @param[in,out] record - Record name
566  * @param[in,out] keyword - Keyword name
567  */
568 void getBackupRecordKeyword(std::string& record, std::string& keyword);
569 
570 } // namespace vpd
571 } // namespace openpower
572