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 * intreface 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 does'nt 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