blob: e526ba103fbcc4eb3eddb01d6bdea32eb8e1b87b [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 {
Tom Joseph4d8d5772021-08-17 07:35:05 -070035 if (activation->activation() ==
36 software::Activation::Activations::Activating)
37 {
38 std::cerr
39 << "Activation of PLDM FW update package already in progress"
40 << ", PACKAGE_VERSION=" << parser->pkgVersion << "\n";
41 std::filesystem::remove(packageFilePath);
42 return -1;
43 }
44 else
45 {
46 clearActivationInfo();
47 }
48 }
49
50 package.open(packageFilePath,
51 std::ios::binary | std::ios::in | std::ios::ate);
52 if (!package.good())
53 {
54 std::cerr << "Opening the PLDM FW update package failed, ERR="
55 << unsigned(errno) << ", PACKAGEFILE=" << packageFilePath
56 << "\n";
57 package.close();
58 std::filesystem::remove(packageFilePath);
59 return -1;
60 }
61
62 uintmax_t packageSize = package.tellg();
63 if (packageSize < sizeof(pldm_package_header_information))
64 {
65 std::cerr << "PLDM FW update package length less than the length of "
66 "the package header information, PACKAGESIZE="
67 << packageSize << "\n";
68 package.close();
69 std::filesystem::remove(packageFilePath);
70 return -1;
71 }
72
73 package.seekg(0);
74 std::vector<uint8_t> packageHeader(sizeof(pldm_package_header_information));
75 package.read(reinterpret_cast<char*>(packageHeader.data()),
76 sizeof(pldm_package_header_information));
77
78 auto pkgHeaderInfo =
79 reinterpret_cast<const pldm_package_header_information*>(
80 packageHeader.data());
81 auto pkgHeaderInfoSize = sizeof(pldm_package_header_information) +
82 pkgHeaderInfo->package_version_string_length;
83 packageHeader.clear();
84 packageHeader.resize(pkgHeaderInfoSize);
85 package.seekg(0);
86 package.read(reinterpret_cast<char*>(packageHeader.data()),
87 pkgHeaderInfoSize);
88
89 parser = parsePkgHeader(packageHeader);
90 if (parser == nullptr)
91 {
92 std::cerr << "Invalid PLDM package header information"
93 << "\n";
94 package.close();
95 std::filesystem::remove(packageFilePath);
96 return -1;
97 }
98
99 // Populate object path with the hash of the package version
100 size_t versionHash = std::hash<std::string>{}(parser->pkgVersion);
101 objPath = swRootPath + std::to_string(versionHash);
102
103 package.seekg(0);
104 packageHeader.resize(parser->pkgHeaderSize);
105 package.read(reinterpret_cast<char*>(packageHeader.data()),
106 parser->pkgHeaderSize);
107 try
108 {
109 parser->parse(packageHeader, packageSize);
110 }
111 catch (const std::exception& e)
112 {
113 std::cerr << "Invalid PLDM package header"
114 << "\n";
115 activation = std::make_unique<Activation>(
116 pldm::utils::DBusHandler::getBus(), objPath,
117 software::Activation::Activations::Invalid, this);
118 package.close();
119 parser.reset();
120 return -1;
121 }
122
123 auto deviceUpdaterInfos =
124 associatePkgToDevices(parser->getFwDeviceIDRecords(), descriptorMap,
125 totalNumComponentUpdates);
126 if (!deviceUpdaterInfos.size())
127 {
128 std::cerr
129 << "No matching devices found with the PLDM firmware update package"
130 << "\n";
131 activation = std::make_unique<Activation>(
132 pldm::utils::DBusHandler::getBus(), objPath,
133 software::Activation::Activations::Invalid, this);
134 package.close();
135 parser.reset();
136 return 0;
137 }
138
139 const auto& fwDeviceIDRecords = parser->getFwDeviceIDRecords();
140 const auto& compImageInfos = parser->getComponentImageInfos();
141
142 for (const auto& deviceUpdaterInfo : deviceUpdaterInfos)
143 {
144 const auto& fwDeviceIDRecord =
145 fwDeviceIDRecords[deviceUpdaterInfo.second];
146 auto search = componentInfoMap.find(deviceUpdaterInfo.first);
Tom Josephb7e083e2021-10-26 15:10:03 +0530147 deviceUpdaterMap.emplace(
148 deviceUpdaterInfo.first,
149 std::make_unique<DeviceUpdater>(
150 deviceUpdaterInfo.first, package, fwDeviceIDRecord,
151 compImageInfos, search->second, MAXIMUM_TRANSFER_SIZE, this));
Tom Joseph4d8d5772021-08-17 07:35:05 -0700152 }
153
154 fwPackageFilePath = packageFilePath;
155 activation = std::make_unique<Activation>(
156 pldm::utils::DBusHandler::getBus(), objPath,
157 software::Activation::Activations::Ready, this);
158 activationProgress = std::make_unique<ActivationProgress>(
159 pldm::utils::DBusHandler::getBus(), objPath);
160
161 return 0;
162}
163
164DeviceUpdaterInfos UpdateManager::associatePkgToDevices(
165 const FirmwareDeviceIDRecords& fwDeviceIDRecords,
166 const DescriptorMap& descriptorMap,
167 TotalComponentUpdates& totalNumComponentUpdates)
168{
169 DeviceUpdaterInfos deviceUpdaterInfos;
170 for (size_t index = 0; index < fwDeviceIDRecords.size(); ++index)
171 {
172 const auto& deviceIDDescriptors =
173 std::get<Descriptors>(fwDeviceIDRecords[index]);
174 for (const auto& [eid, descriptors] : descriptorMap)
175 {
176 if (std::includes(descriptors.begin(), descriptors.end(),
177 deviceIDDescriptors.begin(),
178 deviceIDDescriptors.end()))
179 {
180 deviceUpdaterInfos.emplace_back(std::make_pair(eid, index));
181 const auto& applicableComponents =
182 std::get<ApplicableComponents>(fwDeviceIDRecords[index]);
183 totalNumComponentUpdates += applicableComponents.size();
184 }
185 }
186 }
187 return deviceUpdaterInfos;
188}
189
190void UpdateManager::updateDeviceCompletion(mctp_eid_t eid, bool status)
191{
192 deviceUpdateCompletionMap.emplace(eid, status);
193 if (deviceUpdateCompletionMap.size() == deviceUpdaterMap.size())
194 {
195 for (const auto& [eid, status] : deviceUpdateCompletionMap)
196 {
197 if (!status)
198 {
199 activation->activation(
200 software::Activation::Activations::Failed);
201 return;
202 }
203 }
204
205 auto endTime = std::chrono::steady_clock::now();
206 std::cerr << "Firmware update time: "
207 << std::chrono::duration<double, std::milli>(endTime -
208 startTime)
209 .count()
210 << " ms\n";
211 activation->activation(software::Activation::Activations::Active);
212 }
213 return;
214}
215
216Response 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
260void UpdateManager::activatePackage()
261{
262 startTime = std::chrono::steady_clock::now();
263 for (const auto& [eid, deviceUpdaterPtr] : deviceUpdaterMap)
264 {
265 deviceUpdaterPtr->startFwUpdateFlow();
266 }
267}
268
269void 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
284void 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
294} // namespace pldm