blob: d545645bda675b99438546c511943a78dddd6a22 [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>
P Arun Kumar Reddy6a3f9902025-03-26 10:23:06 +05308#include <sdeventplus/source/event.hpp>
Riya Dixit49cfb132023-03-02 04:26:53 -06009
Tom Joseph4d8d5772021-08-17 07:35:05 -070010#include <cassert>
11#include <cmath>
12#include <filesystem>
13#include <fstream>
14#include <string>
15
Riya Dixit49cfb132023-03-02 04:26:53 -060016PHOSPHOR_LOG2_USING;
17
Tom Joseph4d8d5772021-08-17 07:35:05 -070018namespace pldm
19{
20
21namespace fw_update
22{
23
24namespace fs = std::filesystem;
25namespace software = sdbusplus::xyz::openbmc_project::Software::server;
26
P Arun Kumar Reddy6a3f9902025-03-26 10:23:06 +053027std::string UpdateManager::getSwId()
28{
29 return std::to_string(
30 std::chrono::duration_cast<std::chrono::seconds>(
31 std::chrono::system_clock::now().time_since_epoch())
32 .count());
33}
34
Tom Joseph4d8d5772021-08-17 07:35:05 -070035int UpdateManager::processPackage(const std::filesystem::path& packageFilePath)
36{
37 // If no devices discovered, take no action on the package.
38 if (!descriptorMap.size())
39 {
40 return 0;
41 }
42
43 namespace software = sdbusplus::xyz::openbmc_project::Software::server;
44 // If a firmware activation of a package is in progress, don't proceed with
45 // package processing
46 if (activation)
47 {
Tom Joseph4d8d5772021-08-17 07:35:05 -070048 if (activation->activation() ==
49 software::Activation::Activations::Activating)
50 {
Riya Dixit49cfb132023-03-02 04:26:53 -060051 error(
Riya Dixit76f2c602024-03-28 07:34:12 -050052 "Activation of PLDM fw update package for version '{VERSION}' already in progress.",
53 "VERSION", parser->pkgVersion);
Tom Joseph4d8d5772021-08-17 07:35:05 -070054 std::filesystem::remove(packageFilePath);
55 return -1;
56 }
57 else
58 {
59 clearActivationInfo();
60 }
61 }
62
63 package.open(packageFilePath,
64 std::ios::binary | std::ios::in | std::ios::ate);
65 if (!package.good())
66 {
Riya Dixit49cfb132023-03-02 04:26:53 -060067 error(
Riya Dixit76f2c602024-03-28 07:34:12 -050068 "Failed to open the PLDM fw update package file '{FILE}', error - {ERROR}.",
Riya Dixit1e5c81e2024-05-03 07:54:00 -050069 "ERROR", errno, "FILE", packageFilePath);
Tom Joseph4d8d5772021-08-17 07:35:05 -070070 package.close();
71 std::filesystem::remove(packageFilePath);
72 return -1;
73 }
74
75 uintmax_t packageSize = package.tellg();
P Arun Kumar Reddy6a3f9902025-03-26 10:23:06 +053076
77 auto swId = getSwId();
78 objPath = swRootPath + swId;
79
80 fwPackageFilePath = packageFilePath;
81
82 try
83 {
84 processStream(package, packageSize);
85 return 0;
86 }
87 catch (sdbusplus::exception_t& e)
88 {
89 error("Exception occurred while processing the package: {ERROR}",
90 "ERROR", e);
91 package.close();
92 std::filesystem::remove(packageFilePath);
93 return -1;
94 }
95}
96
97std::string UpdateManager::processStreamDefer(std::istream& package,
98 uintmax_t packageSize)
99{
100 auto swId = getSwId();
101 objPath = swRootPath + swId;
102
103 // If no devices discovered, take no action on the package.
104 if (!descriptorMap.size())
105 {
106 error(
107 "No devices discovered, cannot process the PLDM fw update package.");
108 throw sdbusplus::xyz::openbmc_project::Common::Error::Unavailable();
109 }
110
111 updateDeferHandler = std::make_unique<sdeventplus::source::Defer>(
112 event, [this, &package, packageSize](sdeventplus::source::EventBase&) {
113 this->processStream(package, packageSize);
114 });
115
116 return objPath;
117}
118
119void UpdateManager::processStream(std::istream& package, uintmax_t packageSize)
120{
121 startTime = std::chrono::steady_clock::now();
Tom Joseph4d8d5772021-08-17 07:35:05 -0700122 if (packageSize < sizeof(pldm_package_header_information))
123 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600124 error(
Riya Dixit76f2c602024-03-28 07:34:12 -0500125 "PLDM fw update package length {SIZE} less than the length of the package header information '{PACKAGE_HEADER_INFO_SIZE}'.",
126 "SIZE", packageSize, "PACKAGE_HEADER_INFO_SIZE",
127 sizeof(pldm_package_header_information));
P Arun Kumar Reddy6a3f9902025-03-26 10:23:06 +0530128 activation = std::make_unique<Activation>(
129 pldm::utils::DBusHandler::getBus(), objPath,
130 software::Activation::Activations::Invalid, this);
131 parser.reset();
132 throw sdbusplus::error::xyz::openbmc_project::software::update::
133 InvalidImage();
Tom Joseph4d8d5772021-08-17 07:35:05 -0700134 }
135
136 package.seekg(0);
Unive Tienf357b502025-06-16 15:18:58 +0800137 std::vector<uint8_t> packageHeader(packageSize);
138 package.read(reinterpret_cast<char*>(packageHeader.data()), packageSize);
Tom Joseph4d8d5772021-08-17 07:35:05 -0700139
140 parser = parsePkgHeader(packageHeader);
141 if (parser == nullptr)
142 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600143 error("Invalid PLDM package header information");
P Arun Kumar Reddy6a3f9902025-03-26 10:23:06 +0530144 activation = std::make_unique<Activation>(
145 pldm::utils::DBusHandler::getBus(), objPath,
146 software::Activation::Activations::Invalid, this);
147 parser.reset();
148 throw sdbusplus::error::xyz::openbmc_project::software::update::
149 InvalidImage();
Tom Joseph4d8d5772021-08-17 07:35:05 -0700150 }
151
Tom Joseph4d8d5772021-08-17 07:35:05 -0700152 package.seekg(0);
Tom Joseph4d8d5772021-08-17 07:35:05 -0700153 try
154 {
155 parser->parse(packageHeader, packageSize);
156 }
157 catch (const std::exception& e)
158 {
Riya Dixit76f2c602024-03-28 07:34:12 -0500159 error("Invalid PLDM package header, error - {ERROR}", "ERROR", e);
Tom Joseph4d8d5772021-08-17 07:35:05 -0700160 activation = std::make_unique<Activation>(
161 pldm::utils::DBusHandler::getBus(), objPath,
162 software::Activation::Activations::Invalid, this);
Tom Joseph4d8d5772021-08-17 07:35:05 -0700163 parser.reset();
P Arun Kumar Reddy6a3f9902025-03-26 10:23:06 +0530164 throw sdbusplus::error::xyz::openbmc_project::software::update::
165 InvalidImage();
Tom Joseph4d8d5772021-08-17 07:35:05 -0700166 }
167
168 auto deviceUpdaterInfos =
169 associatePkgToDevices(parser->getFwDeviceIDRecords(), descriptorMap,
170 totalNumComponentUpdates);
171 if (!deviceUpdaterInfos.size())
172 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600173 error(
174 "No matching devices found with the PLDM firmware update package");
Tom Joseph4d8d5772021-08-17 07:35:05 -0700175 activation = std::make_unique<Activation>(
176 pldm::utils::DBusHandler::getBus(), objPath,
177 software::Activation::Activations::Invalid, this);
Tom Joseph4d8d5772021-08-17 07:35:05 -0700178 parser.reset();
P Arun Kumar Reddy6a3f9902025-03-26 10:23:06 +0530179 throw sdbusplus::error::xyz::openbmc_project::software::update::
180 Incompatible();
Tom Joseph4d8d5772021-08-17 07:35:05 -0700181 }
182
183 const auto& fwDeviceIDRecords = parser->getFwDeviceIDRecords();
184 const auto& compImageInfos = parser->getComponentImageInfos();
185
186 for (const auto& deviceUpdaterInfo : deviceUpdaterInfos)
187 {
188 const auto& fwDeviceIDRecord =
189 fwDeviceIDRecords[deviceUpdaterInfo.second];
190 auto search = componentInfoMap.find(deviceUpdaterInfo.first);
Tom Josephb7e083e2021-10-26 15:10:03 +0530191 deviceUpdaterMap.emplace(
192 deviceUpdaterInfo.first,
193 std::make_unique<DeviceUpdater>(
194 deviceUpdaterInfo.first, package, fwDeviceIDRecord,
195 compImageInfos, search->second, MAXIMUM_TRANSFER_SIZE, this));
Tom Joseph4d8d5772021-08-17 07:35:05 -0700196 }
197
Tom Joseph4d8d5772021-08-17 07:35:05 -0700198 activation = std::make_unique<Activation>(
199 pldm::utils::DBusHandler::getBus(), objPath,
200 software::Activation::Activations::Ready, this);
201 activationProgress = std::make_unique<ActivationProgress>(
202 pldm::utils::DBusHandler::getBus(), objPath);
203
P Arun Kumar Reddy6a3f9902025-03-26 10:23:06 +0530204#ifndef FW_UPDATE_INOTIFY_ENABLED
205 activation->activation(software::Activation::Activations::Activating);
206#endif
Tom Joseph4d8d5772021-08-17 07:35:05 -0700207}
208
209DeviceUpdaterInfos UpdateManager::associatePkgToDevices(
210 const FirmwareDeviceIDRecords& fwDeviceIDRecords,
211 const DescriptorMap& descriptorMap,
212 TotalComponentUpdates& totalNumComponentUpdates)
213{
214 DeviceUpdaterInfos deviceUpdaterInfos;
215 for (size_t index = 0; index < fwDeviceIDRecords.size(); ++index)
216 {
217 const auto& deviceIDDescriptors =
218 std::get<Descriptors>(fwDeviceIDRecords[index]);
219 for (const auto& [eid, descriptors] : descriptorMap)
220 {
221 if (std::includes(descriptors.begin(), descriptors.end(),
222 deviceIDDescriptors.begin(),
223 deviceIDDescriptors.end()))
224 {
225 deviceUpdaterInfos.emplace_back(std::make_pair(eid, index));
226 const auto& applicableComponents =
227 std::get<ApplicableComponents>(fwDeviceIDRecords[index]);
228 totalNumComponentUpdates += applicableComponents.size();
229 }
230 }
231 }
232 return deviceUpdaterInfos;
233}
234
235void UpdateManager::updateDeviceCompletion(mctp_eid_t eid, bool status)
236{
237 deviceUpdateCompletionMap.emplace(eid, status);
238 if (deviceUpdateCompletionMap.size() == deviceUpdaterMap.size())
239 {
240 for (const auto& [eid, status] : deviceUpdateCompletionMap)
241 {
242 if (!status)
243 {
244 activation->activation(
245 software::Activation::Activations::Failed);
246 return;
247 }
248 }
249
250 auto endTime = std::chrono::steady_clock::now();
Riya Dixit49cfb132023-03-02 04:26:53 -0600251 auto dur =
252 std::chrono::duration<double, std::milli>(endTime - startTime)
253 .count();
Riya Dixit76f2c602024-03-28 07:34:12 -0500254 info("Firmware update time: {DURATION}ms", "DURATION", dur);
Tom Joseph4d8d5772021-08-17 07:35:05 -0700255 activation->activation(software::Activation::Activations::Active);
256 }
257 return;
258}
259
260Response UpdateManager::handleRequest(mctp_eid_t eid, uint8_t command,
261 const pldm_msg* request, size_t reqMsgLen)
262{
263 Response response(sizeof(pldm_msg), 0);
264 if (deviceUpdaterMap.contains(eid))
265 {
266 auto search = deviceUpdaterMap.find(eid);
267 if (command == PLDM_REQUEST_FIRMWARE_DATA)
268 {
269 return search->second->requestFwData(request, reqMsgLen);
270 }
271 else if (command == PLDM_TRANSFER_COMPLETE)
272 {
273 return search->second->transferComplete(request, reqMsgLen);
274 }
275 else if (command == PLDM_VERIFY_COMPLETE)
276 {
277 return search->second->verifyComplete(request, reqMsgLen);
278 }
279 else if (command == PLDM_APPLY_COMPLETE)
280 {
281 return search->second->applyComplete(request, reqMsgLen);
282 }
283 else
284 {
Pavithra Barithaya1039a8a2025-01-31 11:30:14 +0530285 auto ptr = new (response.data()) pldm_msg;
Tom Joseph4d8d5772021-08-17 07:35:05 -0700286 auto rc = encode_cc_only_resp(
287 request->hdr.instance_id, request->hdr.type,
288 request->hdr.command, PLDM_ERROR_INVALID_DATA, ptr);
289 assert(rc == PLDM_SUCCESS);
290 }
291 }
292 else
293 {
Pavithra Barithaya1039a8a2025-01-31 11:30:14 +0530294 auto ptr = new (response.data()) pldm_msg;
Tom Joseph4d8d5772021-08-17 07:35:05 -0700295 auto rc = encode_cc_only_resp(request->hdr.instance_id,
296 request->hdr.type, +request->hdr.command,
297 PLDM_FWUP_COMMAND_NOT_EXPECTED, ptr);
298 assert(rc == PLDM_SUCCESS);
299 }
300
301 return response;
302}
303
304void UpdateManager::activatePackage()
305{
306 startTime = std::chrono::steady_clock::now();
307 for (const auto& [eid, deviceUpdaterPtr] : deviceUpdaterMap)
308 {
309 deviceUpdaterPtr->startFwUpdateFlow();
310 }
311}
312
313void UpdateManager::clearActivationInfo()
314{
315 activation.reset();
316 activationProgress.reset();
317 objPath.clear();
318
P Arun Kumar Reddy6a3f9902025-03-26 10:23:06 +0530319 if (package.is_open())
320 {
321 package.close();
322 }
Tom Joseph4d8d5772021-08-17 07:35:05 -0700323 deviceUpdaterMap.clear();
324 deviceUpdateCompletionMap.clear();
325 parser.reset();
Tom Joseph4d8d5772021-08-17 07:35:05 -0700326 std::filesystem::remove(fwPackageFilePath);
327 totalNumComponentUpdates = 0;
328 compUpdateCompletedCount = 0;
329}
330
331void UpdateManager::updateActivationProgress()
332{
333 compUpdateCompletedCount++;
334 auto progressPercent = static_cast<uint8_t>(std::floor(
335 (100 * compUpdateCompletedCount) / totalNumComponentUpdates));
336 activationProgress->progress(progressPercent);
337}
338
339} // namespace fw_update
340
Patrick Williams6da4f912023-05-10 07:50:53 -0500341} // namespace pldm