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