blob: 946efb3aa22374aaa16727d02128006d02e56db5 [file] [log] [blame]
Tom Joseph4d8d5772021-08-17 07:35:05 -07001#include "update_manager.hpp"
2
3#include "activation.hpp"
4#include "common/utils.hpp"
5#include "package_parser.hpp"
6
Riya Dixit49cfb132023-03-02 04:26:53 -06007#include <phosphor-logging/lg2.hpp>
8
Tom Joseph4d8d5772021-08-17 07:35:05 -07009#include <cassert>
10#include <cmath>
11#include <filesystem>
12#include <fstream>
13#include <string>
14
Riya Dixit49cfb132023-03-02 04:26:53 -060015PHOSPHOR_LOG2_USING;
16
Tom Joseph4d8d5772021-08-17 07:35:05 -070017namespace pldm
18{
19
20namespace fw_update
21{
22
23namespace fs = std::filesystem;
24namespace software = sdbusplus::xyz::openbmc_project::Software::server;
25
26int 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 Joseph4d8d5772021-08-17 07:35:05 -070039 if (activation->activation() ==
40 software::Activation::Activations::Activating)
41 {
Riya Dixit49cfb132023-03-02 04:26:53 -060042 error(
Riya Dixit76f2c602024-03-28 07:34:12 -050043 "Activation of PLDM fw update package for version '{VERSION}' already in progress.",
44 "VERSION", parser->pkgVersion);
Tom Joseph4d8d5772021-08-17 07:35:05 -070045 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 Dixit49cfb132023-03-02 04:26:53 -060058 error(
Riya Dixit76f2c602024-03-28 07:34:12 -050059 "Failed to open the PLDM fw update package file '{FILE}', error - {ERROR}.",
Riya Dixit1e5c81e2024-05-03 07:54:00 -050060 "ERROR", errno, "FILE", packageFilePath);
Tom Joseph4d8d5772021-08-17 07:35:05 -070061 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 Dixit49cfb132023-03-02 04:26:53 -060069 error(
Riya Dixit76f2c602024-03-28 07:34:12 -050070 "PLDM fw update package length {SIZE} less than the length of the package header information '{PACKAGE_HEADER_INFO_SIZE}'.",
71 "SIZE", packageSize, "PACKAGE_HEADER_INFO_SIZE",
72 sizeof(pldm_package_header_information));
Tom Joseph4d8d5772021-08-17 07:35:05 -070073 package.close();
74 std::filesystem::remove(packageFilePath);
75 return -1;
76 }
77
78 package.seekg(0);
Unive Tienf357b502025-06-16 15:18:58 +080079 std::vector<uint8_t> packageHeader(packageSize);
80 package.read(reinterpret_cast<char*>(packageHeader.data()), packageSize);
Tom Joseph4d8d5772021-08-17 07:35:05 -070081
82 parser = parsePkgHeader(packageHeader);
83 if (parser == nullptr)
84 {
Riya Dixit49cfb132023-03-02 04:26:53 -060085 error("Invalid PLDM package header information");
Tom Joseph4d8d5772021-08-17 07:35:05 -070086 package.close();
87 std::filesystem::remove(packageFilePath);
88 return -1;
89 }
90
91 // Populate object path with the hash of the package version
92 size_t versionHash = std::hash<std::string>{}(parser->pkgVersion);
93 objPath = swRootPath + std::to_string(versionHash);
94
95 package.seekg(0);
Tom Joseph4d8d5772021-08-17 07:35:05 -070096 try
97 {
98 parser->parse(packageHeader, packageSize);
99 }
100 catch (const std::exception& e)
101 {
Riya Dixit76f2c602024-03-28 07:34:12 -0500102 error("Invalid PLDM package header, error - {ERROR}", "ERROR", e);
Tom Joseph4d8d5772021-08-17 07:35:05 -0700103 activation = std::make_unique<Activation>(
104 pldm::utils::DBusHandler::getBus(), objPath,
105 software::Activation::Activations::Invalid, this);
106 package.close();
107 parser.reset();
108 return -1;
109 }
110
111 auto deviceUpdaterInfos =
112 associatePkgToDevices(parser->getFwDeviceIDRecords(), descriptorMap,
113 totalNumComponentUpdates);
114 if (!deviceUpdaterInfos.size())
115 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600116 error(
117 "No matching devices found with the PLDM firmware update package");
Tom Joseph4d8d5772021-08-17 07:35:05 -0700118 activation = std::make_unique<Activation>(
119 pldm::utils::DBusHandler::getBus(), objPath,
120 software::Activation::Activations::Invalid, this);
121 package.close();
122 parser.reset();
123 return 0;
124 }
125
126 const auto& fwDeviceIDRecords = parser->getFwDeviceIDRecords();
127 const auto& compImageInfos = parser->getComponentImageInfos();
128
129 for (const auto& deviceUpdaterInfo : deviceUpdaterInfos)
130 {
131 const auto& fwDeviceIDRecord =
132 fwDeviceIDRecords[deviceUpdaterInfo.second];
133 auto search = componentInfoMap.find(deviceUpdaterInfo.first);
Tom Josephb7e083e2021-10-26 15:10:03 +0530134 deviceUpdaterMap.emplace(
135 deviceUpdaterInfo.first,
136 std::make_unique<DeviceUpdater>(
137 deviceUpdaterInfo.first, package, fwDeviceIDRecord,
138 compImageInfos, search->second, MAXIMUM_TRANSFER_SIZE, this));
Tom Joseph4d8d5772021-08-17 07:35:05 -0700139 }
140
141 fwPackageFilePath = packageFilePath;
142 activation = std::make_unique<Activation>(
143 pldm::utils::DBusHandler::getBus(), objPath,
144 software::Activation::Activations::Ready, this);
145 activationProgress = std::make_unique<ActivationProgress>(
146 pldm::utils::DBusHandler::getBus(), objPath);
147
148 return 0;
149}
150
151DeviceUpdaterInfos UpdateManager::associatePkgToDevices(
152 const FirmwareDeviceIDRecords& fwDeviceIDRecords,
153 const DescriptorMap& descriptorMap,
154 TotalComponentUpdates& totalNumComponentUpdates)
155{
156 DeviceUpdaterInfos deviceUpdaterInfos;
157 for (size_t index = 0; index < fwDeviceIDRecords.size(); ++index)
158 {
159 const auto& deviceIDDescriptors =
160 std::get<Descriptors>(fwDeviceIDRecords[index]);
161 for (const auto& [eid, descriptors] : descriptorMap)
162 {
163 if (std::includes(descriptors.begin(), descriptors.end(),
164 deviceIDDescriptors.begin(),
165 deviceIDDescriptors.end()))
166 {
167 deviceUpdaterInfos.emplace_back(std::make_pair(eid, index));
168 const auto& applicableComponents =
169 std::get<ApplicableComponents>(fwDeviceIDRecords[index]);
170 totalNumComponentUpdates += applicableComponents.size();
171 }
172 }
173 }
174 return deviceUpdaterInfos;
175}
176
177void UpdateManager::updateDeviceCompletion(mctp_eid_t eid, bool status)
178{
179 deviceUpdateCompletionMap.emplace(eid, status);
180 if (deviceUpdateCompletionMap.size() == deviceUpdaterMap.size())
181 {
182 for (const auto& [eid, status] : deviceUpdateCompletionMap)
183 {
184 if (!status)
185 {
186 activation->activation(
187 software::Activation::Activations::Failed);
188 return;
189 }
190 }
191
192 auto endTime = std::chrono::steady_clock::now();
Riya Dixit49cfb132023-03-02 04:26:53 -0600193 auto dur =
194 std::chrono::duration<double, std::milli>(endTime - startTime)
195 .count();
Riya Dixit76f2c602024-03-28 07:34:12 -0500196 info("Firmware update time: {DURATION}ms", "DURATION", dur);
Tom Joseph4d8d5772021-08-17 07:35:05 -0700197 activation->activation(software::Activation::Activations::Active);
198 }
199 return;
200}
201
202Response UpdateManager::handleRequest(mctp_eid_t eid, uint8_t command,
203 const pldm_msg* request, size_t reqMsgLen)
204{
205 Response response(sizeof(pldm_msg), 0);
206 if (deviceUpdaterMap.contains(eid))
207 {
208 auto search = deviceUpdaterMap.find(eid);
209 if (command == PLDM_REQUEST_FIRMWARE_DATA)
210 {
211 return search->second->requestFwData(request, reqMsgLen);
212 }
213 else if (command == PLDM_TRANSFER_COMPLETE)
214 {
215 return search->second->transferComplete(request, reqMsgLen);
216 }
217 else if (command == PLDM_VERIFY_COMPLETE)
218 {
219 return search->second->verifyComplete(request, reqMsgLen);
220 }
221 else if (command == PLDM_APPLY_COMPLETE)
222 {
223 return search->second->applyComplete(request, reqMsgLen);
224 }
225 else
226 {
Pavithra Barithaya1039a8a2025-01-31 11:30:14 +0530227 auto ptr = new (response.data()) pldm_msg;
Tom Joseph4d8d5772021-08-17 07:35:05 -0700228 auto rc = encode_cc_only_resp(
229 request->hdr.instance_id, request->hdr.type,
230 request->hdr.command, PLDM_ERROR_INVALID_DATA, ptr);
231 assert(rc == PLDM_SUCCESS);
232 }
233 }
234 else
235 {
Pavithra Barithaya1039a8a2025-01-31 11:30:14 +0530236 auto ptr = new (response.data()) pldm_msg;
Tom Joseph4d8d5772021-08-17 07:35:05 -0700237 auto rc = encode_cc_only_resp(request->hdr.instance_id,
238 request->hdr.type, +request->hdr.command,
239 PLDM_FWUP_COMMAND_NOT_EXPECTED, ptr);
240 assert(rc == PLDM_SUCCESS);
241 }
242
243 return response;
244}
245
246void UpdateManager::activatePackage()
247{
248 startTime = std::chrono::steady_clock::now();
249 for (const auto& [eid, deviceUpdaterPtr] : deviceUpdaterMap)
250 {
251 deviceUpdaterPtr->startFwUpdateFlow();
252 }
253}
254
255void UpdateManager::clearActivationInfo()
256{
257 activation.reset();
258 activationProgress.reset();
259 objPath.clear();
260
261 deviceUpdaterMap.clear();
262 deviceUpdateCompletionMap.clear();
263 parser.reset();
264 package.close();
265 std::filesystem::remove(fwPackageFilePath);
266 totalNumComponentUpdates = 0;
267 compUpdateCompletedCount = 0;
268}
269
270void UpdateManager::updateActivationProgress()
271{
272 compUpdateCompletedCount++;
273 auto progressPercent = static_cast<uint8_t>(std::floor(
274 (100 * compUpdateCompletedCount) / totalNumComponentUpdates));
275 activationProgress->progress(progressPercent);
276}
277
278} // namespace fw_update
279
Patrick Williams6da4f912023-05-10 07:50:53 -0500280} // namespace pldm