1 #include "firmware_inventory.hpp" 2 3 #include "mdrv2.hpp" 4 5 #include <boost/algorithm/string.hpp> 6 7 #include <fstream> 8 #include <iomanip> 9 #include <iostream> 10 #include <regex> 11 #include <sstream> 12 13 namespace phosphor 14 { 15 namespace smbios 16 { 17 namespace utils 18 { 19 std::vector<std::string> getExistingVersionPaths(sdbusplus::bus_t& bus) 20 { 21 std::vector<std::string> existingVersionPaths; 22 23 auto getVersionPaths = bus.new_method_call( 24 phosphor::smbios::mapperBusName, phosphor::smbios::mapperPath, 25 phosphor::smbios::mapperInterface, "GetSubTreePaths"); 26 getVersionPaths.append(firmwarePath); 27 getVersionPaths.append(0); 28 getVersionPaths.append( 29 std::array<std::string, 1>({phosphor::smbios::versionInterface})); 30 31 try 32 { 33 auto reply = bus.call(getVersionPaths); 34 reply.read(existingVersionPaths); 35 } 36 catch (const sdbusplus::exception_t& e) 37 { 38 lg2::error("Failed to query version objects. ERROR={E}", "E", e.what()); 39 existingVersionPaths.clear(); 40 } 41 42 return existingVersionPaths; 43 } 44 } // namespace utils 45 46 bool FirmwareInventory::getFirmwareInventoryData(uint8_t*& dataIn, 47 int inventoryIndex) 48 { 49 dataIn = getSMBIOSTypePtr(dataIn, firmwareInventoryInformationType); 50 if (dataIn == nullptr) 51 { 52 return false; 53 } 54 for (uint8_t index = 0; index < inventoryIndex; index++) 55 { 56 dataIn = smbiosNextPtr(dataIn); 57 if (dataIn == nullptr) 58 { 59 return false; 60 } 61 dataIn = getSMBIOSTypePtr(dataIn, firmwareInventoryInformationType); 62 if (dataIn == nullptr) 63 { 64 return false; 65 } 66 } 67 return true; 68 } 69 70 void FirmwareInventory::firmwareInfoUpdate(uint8_t* smbiosTableStorage) 71 { 72 uint8_t* dataIn = smbiosTableStorage; 73 if (!getFirmwareInventoryData(dataIn, firmwareInventoryIndex)) 74 { 75 lg2::info("Failed to get data for firmware inventory index {I}", "I", 76 firmwareInventoryIndex); 77 return; 78 } 79 80 auto firmwareInfo = reinterpret_cast<struct FirmwareInfo*>(dataIn); 81 82 firmwareComponentName(firmwareInfo->componentName, firmwareInfo->length, 83 dataIn); 84 firmwareVersion(firmwareInfo->version, firmwareInfo->length, dataIn); 85 firmwareId(firmwareInfo->id, firmwareInfo->length, dataIn); 86 firmwareReleaseDate(firmwareInfo->releaseDate, firmwareInfo->length, 87 dataIn); 88 firmwareManufacturer(firmwareInfo->manufacturer, firmwareInfo->length, 89 dataIn); 90 present(true); 91 purpose(softwareVersion::VersionPurpose::Other); 92 93 std::vector<std::tuple<std::string, std::string, std::string>> assocs; 94 assocs.emplace_back("software_version", "functional", 95 "/xyz/openbmc_project/software"); 96 association::associations(assocs); 97 } 98 99 std::string FirmwareInventory::checkAndCreateFirmwarePath( 100 uint8_t* dataIn, int inventoryIndex, 101 std::vector<std::string>& existingVersionPaths) 102 { 103 if (!getFirmwareInventoryData(dataIn, inventoryIndex)) 104 { 105 lg2::info("Failed to get data for firmware inventory index {I}", "I", 106 inventoryIndex); 107 return ""; 108 } 109 auto firmwareInfo = reinterpret_cast<struct FirmwareInfo*>(dataIn); 110 std::string firmwareId = 111 positionToString(firmwareInfo->id, firmwareInfo->length, dataIn); 112 auto firmwareName = positionToString(firmwareInfo->componentName, 113 firmwareInfo->length, dataIn); 114 std::string firmwareObjPath = ""; 115 #ifdef EXPOSE_FW_COMPONENT_NAME 116 firmwareObjPath = firmwareName; 117 #else 118 firmwareObjPath = firmwareId; 119 #endif 120 if (firmwareInfo->numOfAssociatedComponents > 0) 121 { 122 for (int i = 0; i < firmwareInfo->numOfAssociatedComponents; i++) 123 { 124 auto component = smbiosHandlePtr( 125 dataIn, firmwareInfo->associatedComponentHandles[i]); 126 if (component == nullptr) 127 { 128 continue; 129 } 130 131 auto header = reinterpret_cast<struct StructureHeader*>(component); 132 switch (header->type) 133 { 134 case processorsType: 135 case systemSlots: 136 case onboardDevicesExtended: 137 { 138 auto designation = positionToString( 139 component[4], header->length, component); 140 if (!designation.empty()) 141 { 142 firmwareObjPath.append("_").append(designation); 143 } 144 break; 145 } 146 case systemPowerSupply: 147 { 148 auto location = positionToString(component[5], 149 header->length, component); 150 if (!location.empty()) 151 { 152 firmwareObjPath.append("_").append(location); 153 } 154 break; 155 } 156 default: 157 break; 158 } 159 } 160 } 161 if (firmwareObjPath.empty()) 162 { 163 firmwareObjPath = "firmware" + std::to_string(inventoryIndex); 164 } 165 boost::algorithm::trim_right(firmwareObjPath); 166 firmwareObjPath = 167 std::regex_replace(firmwareObjPath, std::regex("[^a-zA-Z0-9_/]+"), "_"); 168 169 auto eqObjName = [firmwareObjPath](std::string s) { 170 std::filesystem::path p(s); 171 return p.filename().compare(firmwareObjPath) == 0; 172 }; 173 if (std::find_if(existingVersionPaths.begin(), existingVersionPaths.end(), 174 std::move(eqObjName)) != existingVersionPaths.end()) 175 { 176 return ""; 177 } 178 std::string path = firmwarePath; 179 path.append("/").append(firmwareObjPath); 180 return path; 181 } 182 183 void FirmwareInventory::firmwareComponentName( 184 const uint8_t positionNum, const uint8_t structLen, uint8_t* dataIn) 185 { 186 std::string result = positionToString(positionNum, structLen, dataIn); 187 prettyName(result); 188 } 189 190 void FirmwareInventory::firmwareVersion( 191 const uint8_t positionNum, const uint8_t structLen, uint8_t* dataIn) 192 { 193 std::string result = positionToString(positionNum, structLen, dataIn); 194 version(result); 195 } 196 197 void FirmwareInventory::firmwareId(const uint8_t positionNum, 198 const uint8_t structLen, uint8_t* dataIn) 199 { 200 std::string result = positionToString(positionNum, structLen, dataIn); 201 extendedVersion(result); 202 } 203 204 void FirmwareInventory::firmwareReleaseDate( 205 const uint8_t positionNum, const uint8_t structLen, uint8_t* dataIn) 206 { 207 std::string result = positionToString(positionNum, structLen, dataIn); 208 buildDate(result); 209 } 210 211 void FirmwareInventory::firmwareManufacturer( 212 const uint8_t positionNum, const uint8_t structLen, uint8_t* dataIn) 213 { 214 std::string result = positionToString(positionNum, structLen, dataIn); 215 manufacturer(result); 216 } 217 } // namespace smbios 218 } // namespace phosphor 219