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 std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd.c_str(), "r"), 294 pclose); 295 if (!pipe) 296 { 297 throw std::runtime_error("popen() failed!"); 298 } 299 while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) 300 { 301 stdOutput.emplace_back(buffer.data()); 302 } 303 304 return stdOutput; 305 } 306 307 /** @brief This API checks for IM and HW keywords, and based 308 * on these values decides which system json to be used. 309 * @param[in] vpdMap - parsed vpd 310 * @returns System json path 311 */ 312 std::string getSystemsJson(const Parsed& vpdMap); 313 314 /** @brief Reads HW Keyword from the vpd 315 * @param[in] vpdMap - parsed vpd 316 * @returns value of HW Keyword 317 */ 318 const std::string getHW(const Parsed& vpdMap); 319 320 /** @brief Reads IM Keyword from the vpd 321 * @param[in] vpdMap - parsed vpd 322 * @returns value of IM Keyword 323 */ 324 const std::string getIM(const Parsed& vpdMap); 325 326 /** @brief Translate udev event generated path to a generic /sys/bus eeprom path 327 * @param[io] file - path generated from udev event. 328 * @param[in] driver - kernel driver used by the device. 329 */ 330 void udevToGenericPath(std::string& file, const std::string& driver); 331 332 /** 333 * @brief API to generate a vpd name in some pattern. 334 * This vpd-name denotes name of the bad vpd file. 335 * For i2c eeproms - the pattern of the vpd-name will be 336 * i2c-<bus-number>-<eeprom-address>. For spi eeproms - the pattern of the 337 * vpd-name will be spi-<spi-number>. 338 * 339 * @param[in] file - file path of the vpd 340 * @return the vpd-name. 341 */ 342 std::string getBadVpdName(const std::string& file); 343 344 /** 345 * @brief API which dumps the broken/bad vpd in a directory 346 * When the vpd is bad, this api places the bad vpd file inside 347 * "/tmp/bad-vpd" in BMC, in order to collect bad VPD data as a part of user 348 * initiated BMC dump. 349 * 350 * @param[in] file - bad vpd file path 351 * @param[in] vpdVector - bad vpd vector 352 */ 353 void dumpBadVpd(const std::string& file, const Binary& vpdVector); 354 355 /* 356 * @brief This function fetches the value for given keyword in the given record 357 * from vpd data and returns this value. 358 * 359 * @param[in] vpdMap - vpd to find out the data 360 * @param[in] rec - Record under which desired keyword exists 361 * @param[in] kwd - keyword to read the data from 362 * 363 * @returns keyword value if record/keyword combination found 364 * empty string if record or keyword is not found. 365 */ 366 const std::string getKwVal(const Parsed& vpdMap, const std::string& rec, 367 const std::string& kwd); 368 369 /** @brief This creates a complete command using all it's input parameters, 370 * to bind or unbind the driver. 371 * @param[in] devNameAddr - device address on that bus 372 * @param[in] busType - i2c, spi 373 * @param[in] driverType - type of driver like at24 374 * @param[in] bindOrUnbind - either bind or unbind 375 * @returns Command to bind or unbind the driver. 376 */ 377 inline std::string createBindUnbindDriverCmnd(const std::string& devNameAddr, 378 const std::string& busType, 379 const std::string& driverType, 380 const std::string& bindOrUnbind) 381 { 382 return ("echo " + devNameAddr + " > /sys/bus/" + busType + "/drivers/" + 383 driverType + "/" + bindOrUnbind); 384 } 385 386 /** 387 * @brief Get Printable Value 388 * 389 * Checks if the value has non printable characters. 390 * Returns hex value if non printable char is found else 391 * returns ascii value. 392 * 393 * @param[in] kwVal - Reference of the input data, Keyword value 394 * @return printable value - either in hex or in ascii. 395 */ 396 std::string getPrintableValue(const std::variant<Binary, std::string>& kwVal); 397 398 /** 399 * @brief Convert array to hex string. 400 * @param[in] kwVal - input data, Keyword value 401 * @return hexadecimal string of bytes. 402 */ 403 std::string hexString(const std::variant<Binary, std::string>& kwVal); 404 405 /** 406 * @brief Return presence of the FRU. 407 * 408 * This API returns the presence information of the FRU corresponding to the 409 * given EEPROM. If the JSON contains no information about presence detect, this 410 * will return an empty optional. Else it will get the presence GPIO information 411 * from the JSON and return the appropriate present status. 412 * In case of GPIO find/read errors, it will return false. 413 * 414 * @param[in] json - The VPD JSON 415 * @param[in] file - EEPROM file path 416 * @return Empty optional if there is no presence info. Else returns presence 417 * based on the GPIO read. 418 */ 419 std::optional<bool> isPresent(const nlohmann::json& json, 420 const std::string& file); 421 422 /** 423 * @brief Performs any pre-action needed to get the FRU setup for 424 * collection. 425 * 426 * @param[in] json - json object 427 * @param[in] file - eeprom file path 428 * @return - success or failure 429 */ 430 bool executePreAction(const nlohmann::json& json, const std::string& file); 431 432 /** 433 * @brief This API will be called at the end of VPD collection to perform any 434 * post actions. 435 * 436 * @param[in] json - json object 437 * @param[in] file - eeprom file path 438 */ 439 void executePostFailAction(const nlohmann::json& json, const std::string& file); 440 441 /** 442 * @brief Helper function to insert or merge in map. 443 * 444 * This method checks in the given inventory::InterfaceMap if the given 445 * interface key is existing or not. If the interface key already exists, given 446 * property map is inserted into it. If the key does'nt exist then given 447 * interface and property map pair is newly created. If the property present in 448 * propertymap already exist in the InterfaceMap, then the new property value is 449 * ignored. 450 * 451 * @param[in,out] map - map object of type inventory::InterfaceMap only. 452 * @param[in] interface - Interface name. 453 * @param[in] property - new property map that needs to be emplaced. 454 */ 455 void insertOrMerge(inventory::InterfaceMap& map, 456 const inventory::Interface& interface, 457 inventory::PropertyMap&& property); 458 459 /** 460 * @brief Utility API to set a D-Bus property 461 * 462 * This calls org.freedesktop.DBus.Properties;Set method with the supplied 463 * arguments 464 * 465 * @tparam T Template type of the D-Bus property 466 * @param service[in] - The D-Bus service name. 467 * @param object[in] - The D-Bus object on which the property is to be set. 468 * @param interface[in] - The D-Bus interface to which the property belongs. 469 * @param propertyName[in] - The name of the property to set. 470 * @param propertyValue[in] - The value of the property. 471 */ 472 template <typename T> 473 void setBusProperty(const std::string& service, const std::string& object, 474 const std::string& interface, 475 const std::string& propertyName, 476 const std::variant<T>& propertyValue) 477 { 478 try 479 { 480 auto bus = sdbusplus::bus::new_default(); 481 auto method = bus.new_method_call(service.c_str(), object.c_str(), 482 "org.freedesktop.DBus.Properties", 483 "Set"); 484 method.append(interface); 485 method.append(propertyName); 486 method.append(propertyValue); 487 488 bus.call(method); 489 } 490 catch (const sdbusplus::exception::SdBusError& e) 491 { 492 std::cerr << e.what() << std::endl; 493 } 494 } 495 496 /** 497 * @brief Reads BIOS Attribute by name. 498 * 499 * @param attrName[in] - The BIOS attribute name. 500 * @return std::variant<int64_t, std::string> - The BIOS attribute value. 501 */ 502 std::variant<int64_t, std::string> 503 readBIOSAttribute(const std::string& attrName); 504 505 /** 506 * @brief Returns the power state for chassis0 507 * @return The chassis power state. 508 */ 509 std::string getPowerState(); 510 511 /** 512 * @brief Reads VPD from the supplied EEPROM 513 * 514 * This function reads the given VPD EEPROM file and returns its contents as a 515 * byte array. It handles any offsets into the file that need to be taken care 516 * of by looking up the VPD JSON for a possible offset key. 517 * 518 * @param js[in] - The VPD JSON Object 519 * @param file[in] - The path to the EEPROM to read 520 * @return A byte array containing the raw VPD. 521 */ 522 Binary getVpdDataInVector(const nlohmann::json& js, const std::string& file); 523 524 /** 525 * @brief Get D-bus name for the keyword 526 * Some of the VPD keywords has different name in PIM when compared with its 527 * name from hardware. This method returns the D-bus name for the given keyword. 528 * 529 * @param[in] keyword - Keyword name 530 * @return D-bus name for the keyword 531 */ 532 std::string getDbusNameForThisKw(const std::string& keyword); 533 534 /** 535 * @brief API to remove VPD data from Dbus on removal of FRU. 536 * 537 * @param[in] objPath - Inventory path of the FRU. 538 * @param[out] interfacesPropMap - Map of interface, property and value. 539 */ 540 void clearVpdOnRemoval(const std::string& objPath, 541 inventory::InterfaceMap& interfacesPropMap); 542 543 /** 544 * @brief Find backup VPD path if any for the system VPD 545 * 546 * @param[out] backupEepromPath - Backup VPD path 547 * @param[out] backupInvPath - Backup inventory path 548 * @param[in] js - Inventory JSON object 549 */ 550 void findBackupVPDPaths(std::string& backupEepromPath, 551 std::string& backupInvPath, const nlohmann::json& js); 552 553 /** 554 * @brief Get backup VPD's record and keyword for the given system VPD keyword 555 * 556 * @param[in,out] record - Record name 557 * @param[in,out] keyword - Keyword name 558 */ 559 void getBackupRecordKeyword(std::string& record, std::string& keyword); 560 561 } // namespace vpd 562 } // namespace openpower 563