1 #include "update_manager.hpp" 2 3 #include "activation.hpp" 4 #include "common/utils.hpp" 5 #include "package_parser.hpp" 6 7 #include <phosphor-logging/lg2.hpp> 8 9 #include <cassert> 10 #include <cmath> 11 #include <filesystem> 12 #include <fstream> 13 #include <string> 14 15 PHOSPHOR_LOG2_USING; 16 17 namespace pldm 18 { 19 20 namespace fw_update 21 { 22 23 namespace fs = std::filesystem; 24 namespace software = sdbusplus::xyz::openbmc_project::Software::server; 25 26 int UpdateManager::processPackage(const std::filesystem::path& packageFilePath) 27 { 28 // If no devices discovered, take no action on the package. 29 if (!descriptorMap.size()) 30 { 31 return 0; 32 } 33 34 namespace software = sdbusplus::xyz::openbmc_project::Software::server; 35 // If a firmware activation of a package is in progress, don't proceed with 36 // package processing 37 if (activation) 38 { 39 if (activation->activation() == 40 software::Activation::Activations::Activating) 41 { 42 error( 43 "Activation of PLDM FW update package already in progress, PACKAGE_VERSION={PKG_VERS}", 44 "PKG_VERS", parser->pkgVersion); 45 std::filesystem::remove(packageFilePath); 46 return -1; 47 } 48 else 49 { 50 clearActivationInfo(); 51 } 52 } 53 54 package.open(packageFilePath, 55 std::ios::binary | std::ios::in | std::ios::ate); 56 if (!package.good()) 57 { 58 error( 59 "Opening the PLDM FW update package failed, ERR={ERR}, PACKAGEFILE={PKG_FILE}", 60 "ERR", unsigned(errno), "PKG_FILE", packageFilePath.c_str()); 61 package.close(); 62 std::filesystem::remove(packageFilePath); 63 return -1; 64 } 65 66 uintmax_t packageSize = package.tellg(); 67 if (packageSize < sizeof(pldm_package_header_information)) 68 { 69 error( 70 "PLDM FW update package length less than the length of the package header information, PACKAGESIZE={PKG_SIZE}", 71 "PKG_SIZE", packageSize); 72 package.close(); 73 std::filesystem::remove(packageFilePath); 74 return -1; 75 } 76 77 package.seekg(0); 78 std::vector<uint8_t> packageHeader(sizeof(pldm_package_header_information)); 79 package.read(reinterpret_cast<char*>(packageHeader.data()), 80 sizeof(pldm_package_header_information)); 81 82 auto pkgHeaderInfo = 83 reinterpret_cast<const pldm_package_header_information*>( 84 packageHeader.data()); 85 auto pkgHeaderInfoSize = sizeof(pldm_package_header_information) + 86 pkgHeaderInfo->package_version_string_length; 87 packageHeader.clear(); 88 packageHeader.resize(pkgHeaderInfoSize); 89 package.seekg(0); 90 package.read(reinterpret_cast<char*>(packageHeader.data()), 91 pkgHeaderInfoSize); 92 93 parser = parsePkgHeader(packageHeader); 94 if (parser == nullptr) 95 { 96 error("Invalid PLDM package header information"); 97 package.close(); 98 std::filesystem::remove(packageFilePath); 99 return -1; 100 } 101 102 // Populate object path with the hash of the package version 103 size_t versionHash = std::hash<std::string>{}(parser->pkgVersion); 104 objPath = swRootPath + std::to_string(versionHash); 105 106 package.seekg(0); 107 packageHeader.resize(parser->pkgHeaderSize); 108 package.read(reinterpret_cast<char*>(packageHeader.data()), 109 parser->pkgHeaderSize); 110 try 111 { 112 parser->parse(packageHeader, packageSize); 113 } 114 catch (const std::exception& e) 115 { 116 error("Invalid PLDM package header"); 117 activation = std::make_unique<Activation>( 118 pldm::utils::DBusHandler::getBus(), objPath, 119 software::Activation::Activations::Invalid, this); 120 package.close(); 121 parser.reset(); 122 return -1; 123 } 124 125 auto deviceUpdaterInfos = 126 associatePkgToDevices(parser->getFwDeviceIDRecords(), descriptorMap, 127 totalNumComponentUpdates); 128 if (!deviceUpdaterInfos.size()) 129 { 130 error( 131 "No matching devices found with the PLDM firmware update package"); 132 activation = std::make_unique<Activation>( 133 pldm::utils::DBusHandler::getBus(), objPath, 134 software::Activation::Activations::Invalid, this); 135 package.close(); 136 parser.reset(); 137 return 0; 138 } 139 140 const auto& fwDeviceIDRecords = parser->getFwDeviceIDRecords(); 141 const auto& compImageInfos = parser->getComponentImageInfos(); 142 143 for (const auto& deviceUpdaterInfo : deviceUpdaterInfos) 144 { 145 const auto& fwDeviceIDRecord = 146 fwDeviceIDRecords[deviceUpdaterInfo.second]; 147 auto search = componentInfoMap.find(deviceUpdaterInfo.first); 148 deviceUpdaterMap.emplace( 149 deviceUpdaterInfo.first, 150 std::make_unique<DeviceUpdater>( 151 deviceUpdaterInfo.first, package, fwDeviceIDRecord, 152 compImageInfos, search->second, MAXIMUM_TRANSFER_SIZE, this)); 153 } 154 155 fwPackageFilePath = packageFilePath; 156 activation = std::make_unique<Activation>( 157 pldm::utils::DBusHandler::getBus(), objPath, 158 software::Activation::Activations::Ready, this); 159 activationProgress = std::make_unique<ActivationProgress>( 160 pldm::utils::DBusHandler::getBus(), objPath); 161 162 return 0; 163 } 164 165 DeviceUpdaterInfos UpdateManager::associatePkgToDevices( 166 const FirmwareDeviceIDRecords& fwDeviceIDRecords, 167 const DescriptorMap& descriptorMap, 168 TotalComponentUpdates& totalNumComponentUpdates) 169 { 170 DeviceUpdaterInfos deviceUpdaterInfos; 171 for (size_t index = 0; index < fwDeviceIDRecords.size(); ++index) 172 { 173 const auto& deviceIDDescriptors = 174 std::get<Descriptors>(fwDeviceIDRecords[index]); 175 for (const auto& [eid, descriptors] : descriptorMap) 176 { 177 if (std::includes(descriptors.begin(), descriptors.end(), 178 deviceIDDescriptors.begin(), 179 deviceIDDescriptors.end())) 180 { 181 deviceUpdaterInfos.emplace_back(std::make_pair(eid, index)); 182 const auto& applicableComponents = 183 std::get<ApplicableComponents>(fwDeviceIDRecords[index]); 184 totalNumComponentUpdates += applicableComponents.size(); 185 } 186 } 187 } 188 return deviceUpdaterInfos; 189 } 190 191 void UpdateManager::updateDeviceCompletion(mctp_eid_t eid, bool status) 192 { 193 deviceUpdateCompletionMap.emplace(eid, status); 194 if (deviceUpdateCompletionMap.size() == deviceUpdaterMap.size()) 195 { 196 for (const auto& [eid, status] : deviceUpdateCompletionMap) 197 { 198 if (!status) 199 { 200 activation->activation( 201 software::Activation::Activations::Failed); 202 return; 203 } 204 } 205 206 auto endTime = std::chrono::steady_clock::now(); 207 auto dur = 208 std::chrono::duration<double, std::milli>(endTime - startTime) 209 .count(); 210 error("Firmware update time: {DURATION}ms", "DURATION", dur); 211 activation->activation(software::Activation::Activations::Active); 212 } 213 return; 214 } 215 216 Response UpdateManager::handleRequest(mctp_eid_t eid, uint8_t command, 217 const pldm_msg* request, size_t reqMsgLen) 218 { 219 Response response(sizeof(pldm_msg), 0); 220 if (deviceUpdaterMap.contains(eid)) 221 { 222 auto search = deviceUpdaterMap.find(eid); 223 if (command == PLDM_REQUEST_FIRMWARE_DATA) 224 { 225 return search->second->requestFwData(request, reqMsgLen); 226 } 227 else if (command == PLDM_TRANSFER_COMPLETE) 228 { 229 return search->second->transferComplete(request, reqMsgLen); 230 } 231 else if (command == PLDM_VERIFY_COMPLETE) 232 { 233 return search->second->verifyComplete(request, reqMsgLen); 234 } 235 else if (command == PLDM_APPLY_COMPLETE) 236 { 237 return search->second->applyComplete(request, reqMsgLen); 238 } 239 else 240 { 241 auto ptr = reinterpret_cast<pldm_msg*>(response.data()); 242 auto rc = encode_cc_only_resp( 243 request->hdr.instance_id, request->hdr.type, 244 request->hdr.command, PLDM_ERROR_INVALID_DATA, ptr); 245 assert(rc == PLDM_SUCCESS); 246 } 247 } 248 else 249 { 250 auto ptr = reinterpret_cast<pldm_msg*>(response.data()); 251 auto rc = encode_cc_only_resp(request->hdr.instance_id, 252 request->hdr.type, +request->hdr.command, 253 PLDM_FWUP_COMMAND_NOT_EXPECTED, ptr); 254 assert(rc == PLDM_SUCCESS); 255 } 256 257 return response; 258 } 259 260 void UpdateManager::activatePackage() 261 { 262 startTime = std::chrono::steady_clock::now(); 263 for (const auto& [eid, deviceUpdaterPtr] : deviceUpdaterMap) 264 { 265 deviceUpdaterPtr->startFwUpdateFlow(); 266 } 267 } 268 269 void UpdateManager::clearActivationInfo() 270 { 271 activation.reset(); 272 activationProgress.reset(); 273 objPath.clear(); 274 275 deviceUpdaterMap.clear(); 276 deviceUpdateCompletionMap.clear(); 277 parser.reset(); 278 package.close(); 279 std::filesystem::remove(fwPackageFilePath); 280 totalNumComponentUpdates = 0; 281 compUpdateCompletedCount = 0; 282 } 283 284 void UpdateManager::updateActivationProgress() 285 { 286 compUpdateCompletedCount++; 287 auto progressPercent = static_cast<uint8_t>(std::floor( 288 (100 * compUpdateCompletedCount) / totalNumComponentUpdates)); 289 activationProgress->progress(progressPercent); 290 } 291 292 } // namespace fw_update 293 294 } // namespace pldm 295