| Tom Joseph | 4d8d577 | 2021-08-17 07:35:05 -0700 | [diff] [blame] | 1 | #include "update_manager.hpp" | 
 | 2 |  | 
 | 3 | #include "activation.hpp" | 
 | 4 | #include "common/utils.hpp" | 
 | 5 | #include "package_parser.hpp" | 
 | 6 |  | 
| Riya Dixit | 49cfb13 | 2023-03-02 04:26:53 -0600 | [diff] [blame] | 7 | #include <phosphor-logging/lg2.hpp> | 
 | 8 |  | 
| Tom Joseph | 4d8d577 | 2021-08-17 07:35:05 -0700 | [diff] [blame] | 9 | #include <cassert> | 
 | 10 | #include <cmath> | 
 | 11 | #include <filesystem> | 
 | 12 | #include <fstream> | 
 | 13 | #include <string> | 
 | 14 |  | 
| Riya Dixit | 49cfb13 | 2023-03-02 04:26:53 -0600 | [diff] [blame] | 15 | PHOSPHOR_LOG2_USING; | 
 | 16 |  | 
| Tom Joseph | 4d8d577 | 2021-08-17 07:35:05 -0700 | [diff] [blame] | 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 |     { | 
| Tom Joseph | 4d8d577 | 2021-08-17 07:35:05 -0700 | [diff] [blame] | 39 |         if (activation->activation() == | 
 | 40 |             software::Activation::Activations::Activating) | 
 | 41 |         { | 
| Riya Dixit | 49cfb13 | 2023-03-02 04:26:53 -0600 | [diff] [blame] | 42 |             error( | 
 | 43 |                 "Activation of PLDM FW update package already in progress, PACKAGE_VERSION={PKG_VERS}", | 
 | 44 |                 "PKG_VERS", parser->pkgVersion); | 
| Tom Joseph | 4d8d577 | 2021-08-17 07:35:05 -0700 | [diff] [blame] | 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 |     { | 
| Riya Dixit | 49cfb13 | 2023-03-02 04:26:53 -0600 | [diff] [blame] | 58 |         error( | 
 | 59 |             "Opening the PLDM FW update package failed, ERR={ERR}, PACKAGEFILE={PKG_FILE}", | 
 | 60 |             "ERR", unsigned(errno), "PKG_FILE", packageFilePath.c_str()); | 
| Tom Joseph | 4d8d577 | 2021-08-17 07:35:05 -0700 | [diff] [blame] | 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 |     { | 
| Riya Dixit | 49cfb13 | 2023-03-02 04:26:53 -0600 | [diff] [blame] | 69 |         error( | 
 | 70 |             "PLDM FW update package length less than the length of the package header information, PACKAGESIZE={PKG_SIZE}", | 
 | 71 |             "PKG_SIZE", packageSize); | 
| Tom Joseph | 4d8d577 | 2021-08-17 07:35:05 -0700 | [diff] [blame] | 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 |     { | 
| Riya Dixit | 49cfb13 | 2023-03-02 04:26:53 -0600 | [diff] [blame] | 96 |         error("Invalid PLDM package header information"); | 
| Tom Joseph | 4d8d577 | 2021-08-17 07:35:05 -0700 | [diff] [blame] | 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 |     { | 
| Riya Dixit | 49cfb13 | 2023-03-02 04:26:53 -0600 | [diff] [blame] | 116 |         error("Invalid PLDM package header"); | 
| Tom Joseph | 4d8d577 | 2021-08-17 07:35:05 -0700 | [diff] [blame] | 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 |     { | 
| Riya Dixit | 49cfb13 | 2023-03-02 04:26:53 -0600 | [diff] [blame] | 130 |         error( | 
 | 131 |             "No matching devices found with the PLDM firmware update package"); | 
| Tom Joseph | 4d8d577 | 2021-08-17 07:35:05 -0700 | [diff] [blame] | 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); | 
| Tom Joseph | b7e083e | 2021-10-26 15:10:03 +0530 | [diff] [blame] | 148 |         deviceUpdaterMap.emplace( | 
 | 149 |             deviceUpdaterInfo.first, | 
 | 150 |             std::make_unique<DeviceUpdater>( | 
 | 151 |                 deviceUpdaterInfo.first, package, fwDeviceIDRecord, | 
 | 152 |                 compImageInfos, search->second, MAXIMUM_TRANSFER_SIZE, this)); | 
| Tom Joseph | 4d8d577 | 2021-08-17 07:35:05 -0700 | [diff] [blame] | 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(); | 
| Riya Dixit | 49cfb13 | 2023-03-02 04:26:53 -0600 | [diff] [blame] | 207 |         auto dur = | 
 | 208 |             std::chrono::duration<double, std::milli>(endTime - startTime) | 
 | 209 |                 .count(); | 
 | 210 |         error("Firmware update time: {DURATION}ms", "DURATION", dur); | 
| Tom Joseph | 4d8d577 | 2021-08-17 07:35:05 -0700 | [diff] [blame] | 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 |  | 
| Patrick Williams | 6da4f91 | 2023-05-10 07:50:53 -0500 | [diff] [blame] | 294 | } // namespace pldm |