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