blob: 412a420fa260b460f73b3c1e92414e31d25f09d8 [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(
43 "Activation of PLDM FW update package already in progress, PACKAGE_VERSION={PKG_VERS}",
44 "PKG_VERS", 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(
59 "Opening the PLDM FW update package failed, ERR={ERR}, PACKAGEFILE={PKG_FILE}",
60 "ERR", unsigned(errno), "PKG_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(
70 "PLDM FW update package length less than the length of the package header information, PACKAGESIZE={PKG_SIZE}",
71 "PKG_SIZE", packageSize);
Tom Joseph4d8d5772021-08-17 07:35:05 -070072 package.close();
73 std::filesystem::remove(packageFilePath);
74 return -1;
75 }
76
77 package.seekg(0);
78 std::vector<uint8_t> packageHeader(sizeof(pldm_package_header_information));
79 package.read(reinterpret_cast<char*>(packageHeader.data()),
80 sizeof(pldm_package_header_information));
81
82 auto pkgHeaderInfo =
83 reinterpret_cast<const pldm_package_header_information*>(
84 packageHeader.data());
85 auto pkgHeaderInfoSize = sizeof(pldm_package_header_information) +
86 pkgHeaderInfo->package_version_string_length;
87 packageHeader.clear();
88 packageHeader.resize(pkgHeaderInfoSize);
89 package.seekg(0);
90 package.read(reinterpret_cast<char*>(packageHeader.data()),
91 pkgHeaderInfoSize);
92
93 parser = parsePkgHeader(packageHeader);
94 if (parser == nullptr)
95 {
Riya Dixit49cfb132023-03-02 04:26:53 -060096 error("Invalid PLDM package header information");
Tom Joseph4d8d5772021-08-17 07:35:05 -070097 package.close();
98 std::filesystem::remove(packageFilePath);
99 return -1;
100 }
101
102 // Populate object path with the hash of the package version
103 size_t versionHash = std::hash<std::string>{}(parser->pkgVersion);
104 objPath = swRootPath + std::to_string(versionHash);
105
106 package.seekg(0);
107 packageHeader.resize(parser->pkgHeaderSize);
108 package.read(reinterpret_cast<char*>(packageHeader.data()),
109 parser->pkgHeaderSize);
110 try
111 {
112 parser->parse(packageHeader, packageSize);
113 }
114 catch (const std::exception& e)
115 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600116 error("Invalid PLDM package header");
Tom Joseph4d8d5772021-08-17 07:35:05 -0700117 activation = std::make_unique<Activation>(
118 pldm::utils::DBusHandler::getBus(), objPath,
119 software::Activation::Activations::Invalid, this);
120 package.close();
121 parser.reset();
122 return -1;
123 }
124
125 auto deviceUpdaterInfos =
126 associatePkgToDevices(parser->getFwDeviceIDRecords(), descriptorMap,
127 totalNumComponentUpdates);
128 if (!deviceUpdaterInfos.size())
129 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600130 error(
131 "No matching devices found with the PLDM firmware update package");
Tom Joseph4d8d5772021-08-17 07:35:05 -0700132 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();
Riya Dixit49cfb132023-03-02 04:26:53 -0600207 auto dur =
208 std::chrono::duration<double, std::milli>(endTime - startTime)
209 .count();
210 error("Firmware update time: {DURATION}ms", "DURATION", dur);
Tom Joseph4d8d5772021-08-17 07:35:05 -0700211 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