blob: 5e9e98a0f1efb9e56a1a58be3af18c643eb091f5 [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
7#include <cassert>
8#include <cmath>
9#include <filesystem>
10#include <fstream>
11#include <string>
12
13namespace pldm
14{
15
16namespace fw_update
17{
18
19namespace fs = std::filesystem;
20namespace software = sdbusplus::xyz::openbmc_project::Software::server;
21
22int 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);
Tom Josephb7e083e2021-10-26 15:10:03 +0530148 deviceUpdaterMap.emplace(
149 deviceUpdaterInfo.first,
150 std::make_unique<DeviceUpdater>(
151 deviceUpdaterInfo.first, package, fwDeviceIDRecord,
152 compImageInfos, search->second, MAXIMUM_TRANSFER_SIZE, this));
Tom Joseph4d8d5772021-08-17 07:35:05 -0700153 }
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
165DeviceUpdaterInfos 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
191void 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();
207 std::cerr << "Firmware update time: "
208 << std::chrono::duration<double, std::milli>(endTime -
209 startTime)
210 .count()
211 << " ms\n";
212 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
295} // namespace pldm