blob: 428613bc139b272211320609b588883914cb60ae [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}.",
60 "ERROR", unsigned(errno), "FILE", packageFilePath.c_str());
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);
79 std::vector<uint8_t> packageHeader(sizeof(pldm_package_header_information));
80 package.read(reinterpret_cast<char*>(packageHeader.data()),
81 sizeof(pldm_package_header_information));
82
83 auto pkgHeaderInfo =
84 reinterpret_cast<const pldm_package_header_information*>(
85 packageHeader.data());
86 auto pkgHeaderInfoSize = sizeof(pldm_package_header_information) +
87 pkgHeaderInfo->package_version_string_length;
88 packageHeader.clear();
89 packageHeader.resize(pkgHeaderInfoSize);
90 package.seekg(0);
91 package.read(reinterpret_cast<char*>(packageHeader.data()),
92 pkgHeaderInfoSize);
93
94 parser = parsePkgHeader(packageHeader);
95 if (parser == nullptr)
96 {
Riya Dixit49cfb132023-03-02 04:26:53 -060097 error("Invalid PLDM package header information");
Tom Joseph4d8d5772021-08-17 07:35:05 -070098 package.close();
99 std::filesystem::remove(packageFilePath);
100 return -1;
101 }
102
103 // Populate object path with the hash of the package version
104 size_t versionHash = std::hash<std::string>{}(parser->pkgVersion);
105 objPath = swRootPath + std::to_string(versionHash);
106
107 package.seekg(0);
108 packageHeader.resize(parser->pkgHeaderSize);
109 package.read(reinterpret_cast<char*>(packageHeader.data()),
110 parser->pkgHeaderSize);
111 try
112 {
113 parser->parse(packageHeader, packageSize);
114 }
115 catch (const std::exception& e)
116 {
Riya Dixit76f2c602024-03-28 07:34:12 -0500117 error("Invalid PLDM package header, error - {ERROR}", "ERROR", e);
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 -1;
124 }
125
126 auto deviceUpdaterInfos =
127 associatePkgToDevices(parser->getFwDeviceIDRecords(), descriptorMap,
128 totalNumComponentUpdates);
129 if (!deviceUpdaterInfos.size())
130 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600131 error(
132 "No matching devices found with the PLDM firmware update package");
Tom Joseph4d8d5772021-08-17 07:35:05 -0700133 activation = std::make_unique<Activation>(
134 pldm::utils::DBusHandler::getBus(), objPath,
135 software::Activation::Activations::Invalid, this);
136 package.close();
137 parser.reset();
138 return 0;
139 }
140
141 const auto& fwDeviceIDRecords = parser->getFwDeviceIDRecords();
142 const auto& compImageInfos = parser->getComponentImageInfos();
143
144 for (const auto& deviceUpdaterInfo : deviceUpdaterInfos)
145 {
146 const auto& fwDeviceIDRecord =
147 fwDeviceIDRecords[deviceUpdaterInfo.second];
148 auto search = componentInfoMap.find(deviceUpdaterInfo.first);
Tom Josephb7e083e2021-10-26 15:10:03 +0530149 deviceUpdaterMap.emplace(
150 deviceUpdaterInfo.first,
151 std::make_unique<DeviceUpdater>(
152 deviceUpdaterInfo.first, package, fwDeviceIDRecord,
153 compImageInfos, search->second, MAXIMUM_TRANSFER_SIZE, this));
Tom Joseph4d8d5772021-08-17 07:35:05 -0700154 }
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
166DeviceUpdaterInfos 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
192void 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();
Riya Dixit49cfb132023-03-02 04:26:53 -0600208 auto dur =
209 std::chrono::duration<double, std::milli>(endTime - startTime)
210 .count();
Riya Dixit76f2c602024-03-28 07:34:12 -0500211 info("Firmware update time: {DURATION}ms", "DURATION", dur);
Tom Joseph4d8d5772021-08-17 07:35:05 -0700212 activation->activation(software::Activation::Activations::Active);
213 }
214 return;
215}
216
217Response UpdateManager::handleRequest(mctp_eid_t eid, uint8_t command,
218 const pldm_msg* request, size_t reqMsgLen)
219{
220 Response response(sizeof(pldm_msg), 0);
221 if (deviceUpdaterMap.contains(eid))
222 {
223 auto search = deviceUpdaterMap.find(eid);
224 if (command == PLDM_REQUEST_FIRMWARE_DATA)
225 {
226 return search->second->requestFwData(request, reqMsgLen);
227 }
228 else if (command == PLDM_TRANSFER_COMPLETE)
229 {
230 return search->second->transferComplete(request, reqMsgLen);
231 }
232 else if (command == PLDM_VERIFY_COMPLETE)
233 {
234 return search->second->verifyComplete(request, reqMsgLen);
235 }
236 else if (command == PLDM_APPLY_COMPLETE)
237 {
238 return search->second->applyComplete(request, reqMsgLen);
239 }
240 else
241 {
242 auto ptr = reinterpret_cast<pldm_msg*>(response.data());
243 auto rc = encode_cc_only_resp(
244 request->hdr.instance_id, request->hdr.type,
245 request->hdr.command, PLDM_ERROR_INVALID_DATA, ptr);
246 assert(rc == PLDM_SUCCESS);
247 }
248 }
249 else
250 {
251 auto ptr = reinterpret_cast<pldm_msg*>(response.data());
252 auto rc = encode_cc_only_resp(request->hdr.instance_id,
253 request->hdr.type, +request->hdr.command,
254 PLDM_FWUP_COMMAND_NOT_EXPECTED, ptr);
255 assert(rc == PLDM_SUCCESS);
256 }
257
258 return response;
259}
260
261void UpdateManager::activatePackage()
262{
263 startTime = std::chrono::steady_clock::now();
264 for (const auto& [eid, deviceUpdaterPtr] : deviceUpdaterMap)
265 {
266 deviceUpdaterPtr->startFwUpdateFlow();
267 }
268}
269
270void UpdateManager::clearActivationInfo()
271{
272 activation.reset();
273 activationProgress.reset();
274 objPath.clear();
275
276 deviceUpdaterMap.clear();
277 deviceUpdateCompletionMap.clear();
278 parser.reset();
279 package.close();
280 std::filesystem::remove(fwPackageFilePath);
281 totalNumComponentUpdates = 0;
282 compUpdateCompletedCount = 0;
283}
284
285void UpdateManager::updateActivationProgress()
286{
287 compUpdateCompletedCount++;
288 auto progressPercent = static_cast<uint8_t>(std::floor(
289 (100 * compUpdateCompletedCount) / totalNumComponentUpdates));
290 activationProgress->progress(progressPercent);
291}
292
293} // namespace fw_update
294
Patrick Williams6da4f912023-05-10 07:50:53 -0500295} // namespace pldm