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