1 #include "device_updater.hpp"
2
3 #include "activation.hpp"
4 #include "update_manager.hpp"
5
6 #include <libpldm/firmware_update.h>
7
8 #include <phosphor-logging/lg2.hpp>
9
10 #include <functional>
11
12 PHOSPHOR_LOG2_USING;
13
14 namespace pldm
15 {
16
17 namespace fw_update
18 {
19
20 // The highest percentage that component transfer can give
21 static constexpr uint8_t componentXferProgressPercent = 97;
22 static constexpr uint8_t componentVerifyProgressPercent = 98;
23 static constexpr uint8_t componentApplyProgressPercent = 99;
24 static constexpr uint8_t firmwareActivationProgressPercent = 100;
25
UpdateProgress(uint32_t totalSize,mctp_eid_t eid)26 UpdateProgress::UpdateProgress(uint32_t totalSize, mctp_eid_t eid) :
27 progress{}, eid{eid}, totalSize{totalSize}, totalUpdated{},
28 currentState{state::Update}
29 {}
30
getTotalSize() const31 uint32_t UpdateProgress::getTotalSize() const
32 {
33 return totalSize;
34 }
getProgress() const35 uint8_t UpdateProgress::getProgress() const
36 {
37 return progress;
38 }
39
updateState(state newState)40 void UpdateProgress::updateState(state newState)
41 {
42 switch (newState)
43 {
44 case state::Update:
45 break;
46 case state::Verify:
47 progress = componentVerifyProgressPercent;
48 break;
49 case state::Apply:
50 progress = componentApplyProgressPercent;
51 break;
52 default:
53 warning("Invalid state {STATE} provided", "STATE", newState);
54 return;
55 };
56 currentState = newState;
57 }
58
reportFwUpdate(uint32_t amountUpdated)59 void UpdateProgress::reportFwUpdate(uint32_t amountUpdated)
60 {
61 if (currentState != state::Update)
62 {
63 error("invalid state when updating progress: eid {EID}", "EID", eid);
64 return;
65 }
66
67 if (amountUpdated > totalSize)
68 {
69 error("invalid size when updating progress: eid {EID}", "EID", eid);
70 return;
71 }
72
73 if (amountUpdated + totalUpdated > totalSize)
74 {
75 error("invalid total size when updating progress: eid {EID}", "EID",
76 eid);
77 return;
78 }
79
80 if (totalSize == 0)
81 {
82 error("invalid package size when updating progress: eid {EID}", "EID",
83 eid);
84 return;
85 }
86
87 totalUpdated += amountUpdated;
88 progress = static_cast<uint8_t>(std::floor(
89 1.0 * componentXferProgressPercent * totalUpdated / totalSize));
90 return;
91 }
92
DeviceUpdater(mctp_eid_t eid,std::istream & package,const FirmwareDeviceIDRecord & fwDeviceIDRecord,const ComponentImageInfos & compImageInfos,const ComponentInfo & compInfo,uint32_t maxTransferSize,UpdateManager * updateManager)93 DeviceUpdater::DeviceUpdater(
94 mctp_eid_t eid, std::istream& package,
95 const FirmwareDeviceIDRecord& fwDeviceIDRecord,
96 const ComponentImageInfos& compImageInfos, const ComponentInfo& compInfo,
97 uint32_t maxTransferSize, UpdateManager* updateManager) :
98 eid(eid), package(package), fwDeviceIDRecord(fwDeviceIDRecord),
99 compImageInfos(compImageInfos), compInfo(compInfo),
100 maxTransferSize(maxTransferSize), updateManager(updateManager),
101 activationComplete{false}
102 {
103 const auto& applicableComponents =
104 std::get<ApplicableComponents>(fwDeviceIDRecord);
105 // create as many progress objects as there are components
106 // and initialize them with the size of each component
107 for (const auto& applicableComponent : applicableComponents)
108 {
109 const auto& componentSize =
110 std::get<6>(compImageInfos[applicableComponent]);
111 progress.emplace_back(componentSize, eid);
112 }
113 }
114
startFwUpdateFlow()115 void DeviceUpdater::startFwUpdateFlow()
116 {
117 auto instanceIdResult = updateManager->instanceIdDb.next(eid);
118 if (!instanceIdResult)
119 {
120 throw pldm::InstanceIdError(instanceIdResult.error());
121 }
122 auto instanceId = instanceIdResult.value();
123 // NumberOfComponents
124 const auto& applicableComponents =
125 std::get<ApplicableComponents>(fwDeviceIDRecord);
126 // PackageDataLength
127 const auto& fwDevicePkgData =
128 std::get<FirmwareDevicePackageData>(fwDeviceIDRecord);
129 // ComponentImageSetVersionString
130 const auto& compImageSetVersion =
131 std::get<ComponentImageSetVersion>(fwDeviceIDRecord);
132 variable_field compImgSetVerStrInfo{};
133 compImgSetVerStrInfo.ptr =
134 reinterpret_cast<const uint8_t*>(compImageSetVersion.data());
135 compImgSetVerStrInfo.length =
136 static_cast<uint8_t>(compImageSetVersion.size());
137
138 Request request(
139 sizeof(pldm_msg_hdr) + sizeof(struct pldm_request_update_req) +
140 compImgSetVerStrInfo.length);
141 auto requestMsg = new (request.data()) pldm_msg;
142
143 auto rc = encode_request_update_req(
144 instanceId, maxTransferSize, applicableComponents.size(),
145 PLDM_FWUP_MIN_OUTSTANDING_REQ, fwDevicePkgData.size(),
146 PLDM_STR_TYPE_ASCII, compImgSetVerStrInfo.length, &compImgSetVerStrInfo,
147 requestMsg,
148 sizeof(struct pldm_request_update_req) + compImgSetVerStrInfo.length);
149 if (rc)
150 {
151 // Handle error scenario
152 updateManager->instanceIdDb.free(eid, instanceId);
153 error(
154 "Failed to encode request update request for endpoint ID '{EID}', response code '{RC}'",
155 "EID", eid, "RC", rc);
156 }
157
158 rc = updateManager->handler.registerRequest(
159 eid, instanceId, PLDM_FWUP, PLDM_REQUEST_UPDATE, std::move(request),
160 [this](mctp_eid_t eid, const pldm_msg* response, size_t respMsgLen) {
161 this->requestUpdate(eid, response, respMsgLen);
162 });
163 if (rc)
164 {
165 // Handle error scenario
166 error(
167 "Failed to send request update for endpoint ID '{EID}', response code '{RC}'",
168 "EID", eid, "RC", rc);
169 }
170 }
171
requestUpdate(mctp_eid_t eid,const pldm_msg * response,size_t respMsgLen)172 void DeviceUpdater::requestUpdate(mctp_eid_t eid, const pldm_msg* response,
173 size_t respMsgLen)
174 {
175 if (response == nullptr || !respMsgLen)
176 {
177 // Handle error scenario
178 error("No response received for request update for endpoint ID '{EID}'",
179 "EID", eid);
180 updateManager->updateDeviceCompletion(eid, false);
181 return;
182 }
183
184 uint8_t completionCode = 0;
185 uint16_t fdMetaDataLen = 0;
186 uint8_t fdWillSendPkgData = 0;
187
188 auto rc = decode_request_update_resp(response, respMsgLen, &completionCode,
189 &fdMetaDataLen, &fdWillSendPkgData);
190 if (rc)
191 {
192 error(
193 "Failed to decode request update response for endpoint ID '{EID}', response code '{RC}'",
194 "EID", eid, "RC", rc);
195 return;
196 }
197 if (completionCode)
198 {
199 error(
200 "Failure in request update response for endpoint ID '{EID}', completion code '{CC}'",
201 "EID", eid, "CC", completionCode);
202 updateManager->updateDeviceCompletion(eid, false);
203 return;
204 }
205
206 // Optional fields DeviceMetaData and GetPackageData not handled
207 pldmRequest = std::make_unique<sdeventplus::source::Defer>(
208 updateManager->event,
209 std::bind(&DeviceUpdater::sendPassCompTableRequest, this,
210 componentIndex));
211 }
212
sendPassCompTableRequest(size_t offset)213 void DeviceUpdater::sendPassCompTableRequest(size_t offset)
214 {
215 pldmRequest.reset();
216
217 auto instanceIdResult = updateManager->instanceIdDb.next(eid);
218 if (!instanceIdResult)
219 {
220 throw pldm::InstanceIdError(instanceIdResult.error());
221 }
222 auto instanceId = instanceIdResult.value();
223 // TransferFlag
224 const auto& applicableComponents =
225 std::get<ApplicableComponents>(fwDeviceIDRecord);
226 uint8_t transferFlag = 0;
227 if (applicableComponents.size() == 1)
228 {
229 transferFlag = PLDM_START_AND_END;
230 }
231 else if (offset == 0)
232 {
233 transferFlag = PLDM_START;
234 }
235 else if (offset == applicableComponents.size() - 1)
236 {
237 transferFlag = PLDM_END;
238 }
239 else
240 {
241 transferFlag = PLDM_MIDDLE;
242 }
243 const auto& comp = compImageInfos[applicableComponents[offset]];
244 // ComponentClassification
245 CompClassification compClassification = std::get<static_cast<size_t>(
246 ComponentImageInfoPos::CompClassificationPos)>(comp);
247 // ComponentIdentifier
248 CompIdentifier compIdentifier =
249 std::get<static_cast<size_t>(ComponentImageInfoPos::CompIdentifierPos)>(
250 comp);
251 // ComponentClassificationIndex
252 CompClassificationIndex compClassificationIndex{};
253 auto compKey = std::make_pair(compClassification, compIdentifier);
254 if (compInfo.contains(compKey))
255 {
256 auto search = compInfo.find(compKey);
257 compClassificationIndex = search->second;
258 }
259 else
260 {
261 // Handle error scenario
262 error(
263 "Failed to find component classification '{CLASSIFICATION}' and identifier '{IDENTIFIER}'",
264 "CLASSIFICATION", compClassification, "IDENTIFIER", compIdentifier);
265 }
266 // ComponentComparisonStamp
267 CompComparisonStamp compComparisonStamp = std::get<static_cast<size_t>(
268 ComponentImageInfoPos::CompComparisonStampPos)>(comp);
269 // ComponentVersionString
270 const auto& compVersion =
271 std::get<static_cast<size_t>(ComponentImageInfoPos::CompVersionPos)>(
272 comp);
273 variable_field compVerStrInfo{};
274 compVerStrInfo.ptr = reinterpret_cast<const uint8_t*>(compVersion.data());
275 compVerStrInfo.length = static_cast<uint8_t>(compVersion.size());
276
277 Request request(
278 sizeof(pldm_msg_hdr) + sizeof(struct pldm_pass_component_table_req) +
279 compVerStrInfo.length);
280 auto requestMsg = new (request.data()) pldm_msg;
281 auto rc = encode_pass_component_table_req(
282 instanceId, transferFlag, compClassification, compIdentifier,
283 compClassificationIndex, compComparisonStamp, PLDM_STR_TYPE_ASCII,
284 compVerStrInfo.length, &compVerStrInfo, requestMsg,
285 sizeof(pldm_pass_component_table_req) + compVerStrInfo.length);
286 if (rc)
287 {
288 // Handle error scenario
289 updateManager->instanceIdDb.free(eid, instanceId);
290 error(
291 "Failed to encode pass component table req for endpoint ID '{EID}', response code '{RC}'",
292 "EID", eid, "RC", rc);
293 }
294
295 rc = updateManager->handler.registerRequest(
296 eid, instanceId, PLDM_FWUP, PLDM_PASS_COMPONENT_TABLE,
297 std::move(request),
298 [this](mctp_eid_t eid, const pldm_msg* response, size_t respMsgLen) {
299 this->passCompTable(eid, response, respMsgLen);
300 });
301 if (rc)
302 {
303 // Handle error scenario
304 error(
305 "Failed to send pass component table request for endpoint ID '{EID}', response code '{RC}'",
306 "EID", eid, "RC", rc);
307 }
308 }
309
passCompTable(mctp_eid_t eid,const pldm_msg * response,size_t respMsgLen)310 void DeviceUpdater::passCompTable(mctp_eid_t eid, const pldm_msg* response,
311 size_t respMsgLen)
312 {
313 if (response == nullptr || !respMsgLen)
314 {
315 // Handle error scenario
316 error(
317 "No response received for pass component table for endpoint ID '{EID}'",
318 "EID", eid);
319 updateManager->updateDeviceCompletion(eid, false);
320 return;
321 }
322
323 uint8_t completionCode = 0;
324 uint8_t compResponse = 0;
325 uint8_t compResponseCode = 0;
326
327 auto rc =
328 decode_pass_component_table_resp(response, respMsgLen, &completionCode,
329 &compResponse, &compResponseCode);
330 if (rc)
331 {
332 // Handle error scenario
333 error(
334 "Failed to decode pass component table response for endpoint ID '{EID}', response code '{RC}'",
335 "EID", eid, "RC", rc);
336 return;
337 }
338 if (completionCode)
339 {
340 // Handle error scenario
341 error(
342 "Failed to pass component table response for endpoint ID '{EID}', completion code '{CC}'",
343 "EID", eid, "CC", completionCode);
344 updateManager->updateDeviceCompletion(eid, false);
345 return;
346 }
347 // Handle ComponentResponseCode
348
349 const auto& applicableComponents =
350 std::get<ApplicableComponents>(fwDeviceIDRecord);
351 if (componentIndex == applicableComponents.size() - 1)
352 {
353 componentIndex = 0;
354 pldmRequest = std::make_unique<sdeventplus::source::Defer>(
355 updateManager->event,
356 std::bind(&DeviceUpdater::sendUpdateComponentRequest, this,
357 componentIndex));
358 }
359 else
360 {
361 componentIndex++;
362 pldmRequest = std::make_unique<sdeventplus::source::Defer>(
363 updateManager->event,
364 std::bind(&DeviceUpdater::sendPassCompTableRequest, this,
365 componentIndex));
366 }
367 }
368
sendUpdateComponentRequest(size_t offset)369 void DeviceUpdater::sendUpdateComponentRequest(size_t offset)
370 {
371 pldmRequest.reset();
372 auto instanceIdResult = updateManager->instanceIdDb.next(eid);
373 if (!instanceIdResult)
374 {
375 throw pldm::InstanceIdError(instanceIdResult.error());
376 }
377 auto instanceId = instanceIdResult.value();
378 const auto& applicableComponents =
379 std::get<ApplicableComponents>(fwDeviceIDRecord);
380 const auto& comp = compImageInfos[applicableComponents[offset]];
381 // ComponentClassification
382 CompClassification compClassification = std::get<static_cast<size_t>(
383 ComponentImageInfoPos::CompClassificationPos)>(comp);
384 // ComponentIdentifier
385 CompIdentifier compIdentifier =
386 std::get<static_cast<size_t>(ComponentImageInfoPos::CompIdentifierPos)>(
387 comp);
388 // ComponentClassificationIndex
389 CompClassificationIndex compClassificationIndex{};
390 auto compKey = std::make_pair(compClassification, compIdentifier);
391 if (compInfo.contains(compKey))
392 {
393 auto search = compInfo.find(compKey);
394 compClassificationIndex = search->second;
395 }
396 else
397 {
398 // Handle error scenario
399 error(
400 "Failed to find component classification '{CLASSIFICATION}' and identifier '{IDENTIFIER}'",
401 "CLASSIFICATION", compClassification, "IDENTIFIER", compIdentifier);
402 }
403
404 // UpdateOptionFlags
405 bitfield32_t updateOptionFlags;
406 updateOptionFlags.bits.bit0 = std::get<3>(comp)[0];
407 // ComponentVersion
408 const auto& compVersion = std::get<7>(comp);
409 variable_field compVerStrInfo{};
410 compVerStrInfo.ptr = reinterpret_cast<const uint8_t*>(compVersion.data());
411 compVerStrInfo.length = static_cast<uint8_t>(compVersion.size());
412
413 Request request(
414 sizeof(pldm_msg_hdr) + sizeof(struct pldm_update_component_req) +
415 compVerStrInfo.length);
416 auto requestMsg = new (request.data()) pldm_msg;
417
418 auto rc = encode_update_component_req(
419 instanceId, compClassification, compIdentifier, compClassificationIndex,
420 std::get<static_cast<size_t>(
421 ComponentImageInfoPos::CompComparisonStampPos)>(comp),
422 std::get<static_cast<size_t>(ComponentImageInfoPos::CompSizePos)>(comp),
423 updateOptionFlags, PLDM_STR_TYPE_ASCII, compVerStrInfo.length,
424 &compVerStrInfo, requestMsg,
425 sizeof(pldm_update_component_req) + compVerStrInfo.length);
426 if (rc)
427 {
428 // Handle error scenario
429 updateManager->instanceIdDb.free(eid, instanceId);
430 error(
431 "Failed to encode update component req for endpoint ID '{EID}', response code '{RC}'",
432 "EID", eid, "RC", rc);
433 }
434
435 rc = updateManager->handler.registerRequest(
436 eid, instanceId, PLDM_FWUP, PLDM_UPDATE_COMPONENT, std::move(request),
437 [this](mctp_eid_t eid, const pldm_msg* response, size_t respMsgLen) {
438 this->updateComponent(eid, response, respMsgLen);
439 });
440 if (rc)
441 {
442 // Handle error scenario
443 error(
444 "Failed to send update request for endpoint ID '{EID}', response code '{RC}'",
445 "EID", eid, "RC", rc);
446 }
447 }
448
updateComponent(mctp_eid_t eid,const pldm_msg * response,size_t respMsgLen)449 void DeviceUpdater::updateComponent(mctp_eid_t eid, const pldm_msg* response,
450 size_t respMsgLen)
451 {
452 if (response == nullptr || !respMsgLen)
453 {
454 // Handle error scenario
455 error(
456 "No response received for update component with endpoint ID {EID}",
457 "EID", eid);
458 updateManager->updateDeviceCompletion(eid, false);
459 return;
460 }
461
462 uint8_t completionCode = 0;
463 uint8_t compCompatibilityResp = 0;
464 uint8_t compCompatibilityRespCode = 0;
465 bitfield32_t updateOptionFlagsEnabled{};
466 uint16_t timeBeforeReqFWData = 0;
467
468 auto rc = decode_update_component_resp(
469 response, respMsgLen, &completionCode, &compCompatibilityResp,
470 &compCompatibilityRespCode, &updateOptionFlagsEnabled,
471 &timeBeforeReqFWData);
472 if (rc)
473 {
474 error(
475 "Failed to decode update request response for endpoint ID '{EID}', response code '{RC}'",
476 "EID", eid, "RC", rc);
477 return;
478 }
479 if (completionCode)
480 {
481 error(
482 "Failed to update request response for endpoint ID '{EID}', completion code '{CC}'",
483 "EID", eid, "CC", completionCode);
484 return;
485 updateManager->updateDeviceCompletion(eid, false);
486 }
487 }
488
createRequestFwDataTimer()489 void DeviceUpdater::createRequestFwDataTimer()
490 {
491 reqFwDataTimer = std::make_unique<sdbusplus::Timer>([this]() -> void {
492 componentUpdateStatus[componentIndex] = false;
493 sendCancelUpdateComponentRequest();
494 updateManager->updateDeviceCompletion(eid, false);
495 });
496 }
497
requestFwData(const pldm_msg * request,size_t payloadLength)498 Response DeviceUpdater::requestFwData(const pldm_msg* request,
499 size_t payloadLength)
500 {
501 uint8_t completionCode = PLDM_SUCCESS;
502 uint32_t offset = 0;
503 uint32_t length = 0;
504 Response response(sizeof(pldm_msg_hdr) + sizeof(completionCode), 0);
505 auto responseMsg = new (response.data()) pldm_msg;
506 auto rc = decode_request_firmware_data_req(request, payloadLength, &offset,
507 &length);
508 if (rc)
509 {
510 error(
511 "Failed to decode request firmware date request for endpoint ID '{EID}', response code '{RC}'",
512 "EID", eid, "RC", rc);
513 rc = encode_request_firmware_data_resp(
514 request->hdr.instance_id, PLDM_ERROR_INVALID_DATA, responseMsg,
515 sizeof(completionCode));
516 if (rc)
517 {
518 error(
519 "Failed to encode request firmware date response for endpoint ID '{EID}', response code '{RC}'",
520 "EID", eid, "RC", rc);
521 }
522 return response;
523 }
524
525 const auto& applicableComponents =
526 std::get<ApplicableComponents>(fwDeviceIDRecord);
527 const auto& comp = compImageInfos[applicableComponents[componentIndex]];
528 auto compOffset = std::get<5>(comp);
529 auto compSize = std::get<6>(comp);
530 debug("Decoded fw request data at offset '{OFFSET}' and length '{LENGTH}' ",
531 "OFFSET", offset, "LENGTH", length);
532 if (length < PLDM_FWUP_BASELINE_TRANSFER_SIZE || length > maxTransferSize)
533 {
534 rc = encode_request_firmware_data_resp(
535 request->hdr.instance_id, PLDM_FWUP_INVALID_TRANSFER_LENGTH,
536 responseMsg, sizeof(completionCode));
537 if (rc)
538 {
539 error(
540 "Failed to encode request firmware date response for endpoint ID '{EID}', response code '{RC}'",
541 "EID", eid, "RC", rc);
542 }
543 return response;
544 }
545
546 if (offset + length > compSize + PLDM_FWUP_BASELINE_TRANSFER_SIZE)
547 {
548 rc = encode_request_firmware_data_resp(
549 request->hdr.instance_id, PLDM_FWUP_DATA_OUT_OF_RANGE, responseMsg,
550 sizeof(completionCode));
551 if (rc)
552 {
553 error(
554 "Failed to encode request firmware date response for endpoint ID '{EID}', response code '{RC}'",
555 "EID", eid, "RC", rc);
556 }
557 return response;
558 }
559
560 size_t padBytes = 0;
561 if (offset + length > compSize)
562 {
563 padBytes = offset + length - compSize;
564 }
565
566 if (componentIndex < progress.size())
567 {
568 // technically this should never happen, as its an invariant
569 // but check to prefer a failed fw update over a pldm crash
570 progress[componentIndex].reportFwUpdate(length);
571 if (updateManager != nullptr)
572 {
573 updateManager->updateActivationProgress();
574 }
575 }
576
577 response.resize(sizeof(pldm_msg_hdr) + sizeof(completionCode) + length);
578 responseMsg = new (response.data()) pldm_msg;
579 package.seekg(compOffset + offset);
580 package.read(
581 reinterpret_cast<char*>(
582 response.data() + sizeof(pldm_msg_hdr) + sizeof(completionCode)),
583 length - padBytes);
584 rc = encode_request_firmware_data_resp(
585 request->hdr.instance_id, completionCode, responseMsg,
586 sizeof(completionCode));
587 if (rc)
588 {
589 error(
590 "Failed to encode request firmware date response for endpoint ID '{EID}', response code '{RC}'",
591 "EID", eid, "RC", rc);
592 return response;
593 }
594
595 if (!reqFwDataTimer)
596 {
597 if (offset != 0)
598 {
599 warning("First data request is not at offset 0");
600 }
601 createRequestFwDataTimer();
602 }
603
604 if (reqFwDataTimer)
605 {
606 reqFwDataTimer->start(std::chrono::seconds(updateTimeoutSeconds),
607 false);
608 }
609 else
610 {
611 error(
612 "Failed to start timer for handling request firmware data for endpoint ID {EID}",
613 "EID", eid, "RC", rc);
614 }
615
616 return response;
617 }
618
transferComplete(const pldm_msg * request,size_t payloadLength)619 Response DeviceUpdater::transferComplete(const pldm_msg* request,
620 size_t payloadLength)
621 {
622 uint8_t completionCode = PLDM_SUCCESS;
623 Response response(sizeof(pldm_msg_hdr) + sizeof(completionCode), 0);
624 auto responseMsg = new (response.data()) pldm_msg;
625
626 if (reqFwDataTimer)
627 {
628 reqFwDataTimer->stop();
629 reqFwDataTimer.reset();
630 }
631
632 uint8_t transferResult = 0;
633 auto rc =
634 decode_transfer_complete_req(request, payloadLength, &transferResult);
635 if (rc)
636 {
637 error(
638 "Failed to decode TransferComplete request for endpoint ID '{EID}', response code '{RC}'",
639 "EID", eid, "RC", rc);
640 rc = encode_transfer_complete_resp(request->hdr.instance_id,
641 PLDM_ERROR_INVALID_DATA, responseMsg,
642 sizeof(completionCode));
643 if (rc)
644 {
645 error(
646 "Failed to encode TransferComplete response for endpoint ID '{EID}', response code '{RC}'",
647 "EID", eid, "RC", rc);
648 }
649 return response;
650 }
651
652 const auto& applicableComponents =
653 std::get<ApplicableComponents>(fwDeviceIDRecord);
654 const auto& comp = compImageInfos[applicableComponents[componentIndex]];
655 const auto& compVersion = std::get<7>(comp);
656
657 if (transferResult == PLDM_FWUP_TRANSFER_SUCCESS)
658 {
659 info(
660 "Component endpoint ID '{EID}' and version '{COMPONENT_VERSION}' transfer complete.",
661 "EID", eid, "COMPONENT_VERSION", compVersion);
662 }
663 else
664 {
665 error(
666 "Failure in transfer of the component endpoint ID '{EID}' and version '{COMPONENT_VERSION}' with transfer result - {RESULT}",
667 "EID", eid, "COMPONENT_VERSION", compVersion, "RESULT",
668 transferResult);
669 updateManager->updateDeviceCompletion(eid, false);
670 componentUpdateStatus[componentIndex] = false;
671 sendCancelUpdateComponentRequest();
672 }
673
674 rc = encode_transfer_complete_resp(request->hdr.instance_id, completionCode,
675 responseMsg, sizeof(completionCode));
676 if (rc)
677 {
678 error(
679 "Failed to encode transfer complete response of endpoint ID '{EID}', response code '{RC}'",
680 "EID", eid, "RC", rc);
681 return response;
682 }
683
684 return response;
685 }
686
verifyComplete(const pldm_msg * request,size_t payloadLength)687 Response DeviceUpdater::verifyComplete(const pldm_msg* request,
688 size_t payloadLength)
689 {
690 uint8_t completionCode = PLDM_SUCCESS;
691 Response response(sizeof(pldm_msg_hdr) + sizeof(completionCode), 0);
692 auto responseMsg = new (response.data()) pldm_msg;
693
694 uint8_t verifyResult = 0;
695 auto rc = decode_verify_complete_req(request, payloadLength, &verifyResult);
696 if (rc)
697 {
698 error(
699 "Failed to decode verify complete request of endpoint ID '{EID}', response code '{RC}'",
700 "EID", eid, "RC", rc);
701 rc = encode_verify_complete_resp(request->hdr.instance_id,
702 PLDM_ERROR_INVALID_DATA, responseMsg,
703 sizeof(completionCode));
704 if (rc)
705 {
706 error(
707 "Failed to encode verify complete response of endpoint ID '{EID}', response code '{RC}'.",
708 "EID", eid, "RC", rc);
709 }
710 return response;
711 }
712
713 const auto& applicableComponents =
714 std::get<ApplicableComponents>(fwDeviceIDRecord);
715 const auto& comp = compImageInfos[applicableComponents[componentIndex]];
716 const auto& compVersion = std::get<7>(comp);
717 if (componentIndex < progress.size())
718 {
719 progress[componentIndex].updateState(UpdateProgress::state::Verify);
720 if (updateManager != nullptr)
721 {
722 updateManager->updateActivationProgress();
723 }
724 }
725 if (verifyResult == PLDM_FWUP_VERIFY_SUCCESS)
726 {
727 info(
728 "Component endpoint ID '{EID}' and version '{COMPONENT_VERSION}' verification complete.",
729 "EID", eid, "COMPONENT_VERSION", compVersion);
730 }
731 else
732 {
733 error(
734 "Failed to verify component endpoint ID '{EID}' and version '{COMPONENT_VERSION}' with transfer result - '{RESULT}'",
735 "EID", eid, "COMPONENT_VERSION", compVersion, "RESULT",
736 verifyResult);
737 updateManager->updateDeviceCompletion(eid, false);
738 componentUpdateStatus[componentIndex] = false;
739 sendCancelUpdateComponentRequest();
740 }
741
742 rc = encode_verify_complete_resp(request->hdr.instance_id, completionCode,
743 responseMsg, sizeof(completionCode));
744 if (rc)
745 {
746 error(
747 "Failed to encode verify complete response for endpoint ID '{EID}', response code - {RC}",
748 "EID", eid, "RC", rc);
749 return response;
750 }
751
752 return response;
753 }
754
applyComplete(const pldm_msg * request,size_t payloadLength)755 Response DeviceUpdater::applyComplete(const pldm_msg* request,
756 size_t payloadLength)
757 {
758 uint8_t completionCode = PLDM_SUCCESS;
759 Response response(sizeof(pldm_msg_hdr) + sizeof(completionCode), 0);
760 auto responseMsg = new (response.data()) pldm_msg;
761
762 uint8_t applyResult = 0;
763 bitfield16_t compActivationModification{};
764 auto rc = decode_apply_complete_req(request, payloadLength, &applyResult,
765 &compActivationModification);
766 if (rc)
767 {
768 error(
769 "Failed to decode apply complete request for endpoint ID '{EID}', response code '{RC}'",
770 "EID", eid, "RC", rc);
771 rc = encode_apply_complete_resp(request->hdr.instance_id,
772 PLDM_ERROR_INVALID_DATA, responseMsg,
773 sizeof(completionCode));
774 if (rc)
775 {
776 error(
777 "Failed to encode apply complete response for endpoint ID '{EID}', response code '{RC}'",
778 "EID", eid, "RC", rc);
779 }
780 return response;
781 }
782
783 const auto& applicableComponents =
784 std::get<ApplicableComponents>(fwDeviceIDRecord);
785 const auto& comp = compImageInfos[applicableComponents[componentIndex]];
786 const auto& compVersion = std::get<7>(comp);
787
788 if (applyResult == PLDM_FWUP_APPLY_SUCCESS ||
789 applyResult == PLDM_FWUP_APPLY_SUCCESS_WITH_ACTIVATION_METHOD)
790 {
791 info(
792 "Component endpoint ID '{EID}' with '{COMPONENT_VERSION}' apply complete.",
793 "EID", eid, "COMPONENT_VERSION", compVersion);
794 if (componentIndex < progress.size())
795 {
796 progress[componentIndex].updateState(UpdateProgress::state::Apply);
797 if (updateManager != nullptr)
798 {
799 updateManager->updateActivationProgress();
800 }
801 }
802 if (componentIndex == applicableComponents.size() - 1)
803 {
804 componentIndex = 0;
805 componentUpdateStatus.clear();
806 componentUpdateStatus[componentIndex] = true;
807 if (updateManager != nullptr)
808 {
809 pldmRequest = std::make_unique<sdeventplus::source::Defer>(
810 updateManager->event,
811 std::bind(&DeviceUpdater::sendActivateFirmwareRequest,
812 this));
813 }
814 }
815 else
816 {
817 componentIndex++;
818 componentUpdateStatus[componentIndex] = true;
819 if (updateManager != nullptr)
820 {
821 pldmRequest = std::make_unique<sdeventplus::source::Defer>(
822 updateManager->event,
823 std::bind(&DeviceUpdater::sendUpdateComponentRequest, this,
824 componentIndex));
825 }
826 }
827 }
828 else
829 {
830 error(
831 "Failed to apply component endpoint ID '{EID}' and version '{COMPONENT_VERSION}', error - {ERROR}",
832 "EID", eid, "COMPONENT_VERSION", compVersion, "ERROR", applyResult);
833 if (updateManager != nullptr)
834 {
835 updateManager->updateDeviceCompletion(eid, false);
836 }
837 componentUpdateStatus[componentIndex] = false;
838 sendCancelUpdateComponentRequest();
839 }
840
841 rc = encode_apply_complete_resp(request->hdr.instance_id, completionCode,
842 responseMsg, sizeof(completionCode));
843 if (rc)
844 {
845 error(
846 "Failed to encode apply complete response for endpoint ID '{EID}', response code '{RC}'",
847 "EID", eid, "RC", rc);
848 return response;
849 }
850
851 return response;
852 }
853
sendActivateFirmwareRequest()854 void DeviceUpdater::sendActivateFirmwareRequest()
855 {
856 pldmRequest.reset();
857 auto instanceIdResult = updateManager->instanceIdDb.next(eid);
858 if (!instanceIdResult)
859 {
860 throw pldm::InstanceIdError(instanceIdResult.error());
861 }
862 auto instanceId = instanceIdResult.value();
863 Request request(
864 sizeof(pldm_msg_hdr) + sizeof(struct pldm_activate_firmware_req));
865 auto requestMsg = new (request.data()) pldm_msg;
866
867 auto rc = encode_activate_firmware_req(
868 instanceId, PLDM_NOT_ACTIVATE_SELF_CONTAINED_COMPONENTS, requestMsg,
869 sizeof(pldm_activate_firmware_req));
870 if (rc)
871 {
872 updateManager->instanceIdDb.free(eid, instanceId);
873 error(
874 "Failed to encode activate firmware req for endpoint ID '{EID}', response code '{RC}'",
875 "EID", eid, "RC", rc);
876 }
877
878 rc = updateManager->handler.registerRequest(
879 eid, instanceId, PLDM_FWUP, PLDM_ACTIVATE_FIRMWARE, std::move(request),
880 [this](mctp_eid_t eid, const pldm_msg* response, size_t respMsgLen) {
881 this->activateFirmware(eid, response, respMsgLen);
882 });
883 if (rc)
884 {
885 error(
886 "Failed to send activate firmware request for endpoint ID '{EID}', response code '{RC}'",
887 "EID", eid, "RC", rc);
888 }
889 }
890
activateFirmware(mctp_eid_t eid,const pldm_msg * response,size_t respMsgLen)891 void DeviceUpdater::activateFirmware(mctp_eid_t eid, const pldm_msg* response,
892 size_t respMsgLen)
893 {
894 if (response == nullptr || !respMsgLen)
895 {
896 // Handle error scenario
897 error(
898 "No response received for activate firmware for endpoint ID '{EID}'",
899 "EID", eid);
900 updateManager->updateDeviceCompletion(eid, false);
901 return;
902 }
903
904 uint8_t completionCode = 0;
905 uint16_t estimatedTimeForActivation = 0;
906
907 auto rc = decode_activate_firmware_resp(
908 response, respMsgLen, &completionCode, &estimatedTimeForActivation);
909 if (rc)
910 {
911 // Handle error scenario
912 error(
913 "Failed to decode activate firmware response for endpoint ID '{EID}', response code '{RC}'",
914 "EID", eid, "RC", rc);
915 return;
916 }
917 if (completionCode)
918 {
919 // Handle error scenario
920 error(
921 "Failed to activate firmware response for endpoint ID '{EID}', completion code '{CC}'",
922 "EID", eid, "CC", completionCode);
923 updateManager->updateDeviceCompletion(eid, false);
924 return;
925 }
926
927 activationComplete = true;
928 if (updateManager == nullptr)
929 {
930 return;
931 }
932
933 updateManager->updateActivationProgress();
934 updateManager->updateDeviceCompletion(eid, true);
935 }
936
sendCancelUpdateComponentRequest()937 void DeviceUpdater::sendCancelUpdateComponentRequest()
938 {
939 pldmRequest.reset();
940 auto instanceIdResult = updateManager->instanceIdDb.next(eid);
941 if (!instanceIdResult)
942 {
943 throw pldm::InstanceIdError(instanceIdResult.error());
944 }
945 auto instanceId = instanceIdResult.value();
946 Request request(sizeof(pldm_msg_hdr));
947 auto requestMsg = new (request.data()) pldm_msg;
948
949 auto rc = encode_cancel_update_component_req(
950 instanceId, requestMsg, PLDM_CANCEL_UPDATE_COMPONENT_REQ_BYTES);
951 if (rc)
952 {
953 updateManager->instanceIdDb.free(eid, instanceId);
954 error(
955 "Failed to encode cancel update component request for endpoint ID '{EID}', component index '{COMPONENT_INDEX}', response code '{RC}'",
956 "EID", eid, "COMPONENT_INDEX", componentIndex, "RC", rc);
957 return;
958 }
959
960 rc = updateManager->handler.registerRequest(
961 eid, instanceId, PLDM_FWUP, PLDM_CANCEL_UPDATE_COMPONENT,
962 std::move(request),
963 [this](mctp_eid_t eid, const pldm_msg* response, size_t respMsgLen) {
964 this->cancelUpdateComponent(eid, response, respMsgLen);
965 });
966 if (rc)
967 {
968 error(
969 "Failed to send cancel update component request for endpoint ID '{EID}', component index '{COMPONENT_INDEX}', response code '{RC}'",
970 "EID", eid, "COMPONENT_INDEX", componentIndex, "RC", rc);
971 }
972 }
973
cancelUpdateComponent(mctp_eid_t eid,const pldm_msg * response,size_t respMsgLen)974 void DeviceUpdater::cancelUpdateComponent(
975 mctp_eid_t eid, const pldm_msg* response, size_t respMsgLen)
976 {
977 // Check if response is valid
978 if (response == nullptr || !respMsgLen)
979 {
980 error(
981 "No response received for cancel update component for endpoint ID '{EID}'",
982 "EID", eid);
983 return;
984 }
985
986 uint8_t completionCode = 0;
987 auto rc = decode_cancel_update_component_resp(response, respMsgLen,
988 &completionCode);
989 if (rc)
990 {
991 error(
992 "Failed to decode cancel update component response for endpoint ID '{EID}', component index '{COMPONENT_INDEX}', completion code '{CC}'",
993 "EID", eid, "COMPONENT_INDEX", componentIndex, "CC",
994 completionCode);
995 return;
996 }
997 if (completionCode)
998 {
999 error(
1000 "Failed to cancel update component for endpoint ID '{EID}', component index '{COMPONENT_INDEX}', completion code '{CC}'",
1001 "EID", eid, "COMPONENT_INDEX", componentIndex, "CC",
1002 completionCode);
1003 return;
1004 }
1005
1006 const auto& applicableComponents =
1007 std::get<ApplicableComponents>(fwDeviceIDRecord);
1008 // Check if this is the last component being cancelled
1009 if (componentIndex == applicableComponents.size() - 1)
1010 {
1011 for (auto& compStatus : componentUpdateStatus)
1012 {
1013 if (compStatus.second)
1014 {
1015 // If at least one component update succeeded, proceed with
1016 // activation
1017 componentIndex = 0;
1018 componentUpdateStatus.clear();
1019 pldmRequest = std::make_unique<sdeventplus::source::Defer>(
1020 updateManager->event,
1021 std::bind(&DeviceUpdater::sendActivateFirmwareRequest,
1022 this));
1023 return;
1024 }
1025 }
1026 updateManager->updateDeviceCompletion(eid, false);
1027 }
1028 else
1029 {
1030 // Move to next component and update its status
1031 componentIndex++;
1032 componentUpdateStatus[componentIndex] = true;
1033 pldmRequest = std::make_unique<sdeventplus::source::Defer>(
1034 updateManager->event,
1035 std::bind(&DeviceUpdater::sendUpdateComponentRequest, this,
1036 componentIndex));
1037 }
1038 return;
1039 }
1040
getProgress() const1041 uint8_t DeviceUpdater::getProgress() const
1042 {
1043 if (progress.empty())
1044 {
1045 return 0;
1046 }
1047
1048 if (activationComplete)
1049 {
1050 return firmwareActivationProgressPercent;
1051 }
1052
1053 uint64_t totalSize = 0;
1054 uint64_t weightedProgress = 0;
1055 for (const auto& el : progress)
1056 {
1057 totalSize += el.getTotalSize();
1058 weightedProgress +=
1059 el.getTotalSize() * static_cast<uint64_t>(el.getProgress());
1060 }
1061
1062 if (totalSize == 0)
1063 {
1064 error("total component size is 0 on eid {EID}", "EID", eid);
1065 return 0;
1066 }
1067
1068 const double percentage =
1069 static_cast<double>(weightedProgress) / static_cast<double>(totalSize);
1070
1071 return static_cast<uint8_t>(std::floor(percentage));
1072 }
1073
1074 } // namespace fw_update
1075
1076 } // namespace pldm
1077