blob: 4009a481e181fb98a768080620da69250180bf4d [file] [log] [blame]
#include "device_updater.hpp"
#include "activation.hpp"
#include "update_manager.hpp"
#include <libpldm/firmware_update.h>
#include <phosphor-logging/lg2.hpp>
#include <functional>
PHOSPHOR_LOG2_USING;
namespace pldm
{
namespace fw_update
{
void DeviceUpdater::startFwUpdateFlow()
{
auto instanceId = updateManager->requester.getInstanceId(eid);
// NumberOfComponents
const auto& applicableComponents =
std::get<ApplicableComponents>(fwDeviceIDRecord);
// PackageDataLength
const auto& fwDevicePkgData =
std::get<FirmwareDevicePackageData>(fwDeviceIDRecord);
// ComponentImageSetVersionString
const auto& compImageSetVersion =
std::get<ComponentImageSetVersion>(fwDeviceIDRecord);
variable_field compImgSetVerStrInfo{};
compImgSetVerStrInfo.ptr =
reinterpret_cast<const uint8_t*>(compImageSetVersion.data());
compImgSetVerStrInfo.length =
static_cast<uint8_t>(compImageSetVersion.size());
Request request(sizeof(pldm_msg_hdr) +
sizeof(struct pldm_request_update_req) +
compImgSetVerStrInfo.length);
auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
auto rc = encode_request_update_req(
instanceId, maxTransferSize, applicableComponents.size(),
PLDM_FWUP_MIN_OUTSTANDING_REQ, fwDevicePkgData.size(),
PLDM_STR_TYPE_ASCII, compImgSetVerStrInfo.length, &compImgSetVerStrInfo,
requestMsg,
sizeof(struct pldm_request_update_req) + compImgSetVerStrInfo.length);
if (rc)
{
updateManager->requester.markFree(eid, instanceId);
error("encode_request_update_req failed, EID = {EID}, RC = {RC}", "EID",
unsigned(eid), "RC", rc);
// Handle error scenario
}
rc = updateManager->handler.registerRequest(
eid, instanceId, PLDM_FWUP, PLDM_REQUEST_UPDATE, std::move(request),
std::move(std::bind_front(&DeviceUpdater::requestUpdate, this)));
if (rc)
{
error("Failed to send RequestUpdate request, EID = {EID}, RC = {RC}",
"EID", unsigned(eid), "RC", rc);
// Handle error scenario
}
}
void DeviceUpdater::requestUpdate(mctp_eid_t eid, const pldm_msg* response,
size_t respMsgLen)
{
if (response == nullptr || !respMsgLen)
{
// Handle error scenario
error("No response received for RequestUpdate, EID = {EID}", "EID",
unsigned(eid));
return;
}
uint8_t completionCode = 0;
uint16_t fdMetaDataLen = 0;
uint8_t fdWillSendPkgData = 0;
auto rc = decode_request_update_resp(response, respMsgLen, &completionCode,
&fdMetaDataLen, &fdWillSendPkgData);
if (rc)
{
error("Decoding RequestUpdate response failed, EID = {EID}, RC = {RC}",
"EID", unsigned(eid), "RC", rc);
return;
}
if (completionCode)
{
error(
"RequestUpdate response failed with error completion code, EID = {EID}, CC = {CC}",
"EID", unsigned(eid), "CC", unsigned(completionCode));
return;
}
// Optional fields DeviceMetaData and GetPackageData not handled
pldmRequest = std::make_unique<sdeventplus::source::Defer>(
updateManager->event,
std::bind(&DeviceUpdater::sendPassCompTableRequest, this,
componentIndex));
}
void DeviceUpdater::sendPassCompTableRequest(size_t offset)
{
pldmRequest.reset();
auto instanceId = updateManager->requester.getInstanceId(eid);
// TransferFlag
const auto& applicableComponents =
std::get<ApplicableComponents>(fwDeviceIDRecord);
uint8_t transferFlag = 0;
if (applicableComponents.size() == 1)
{
transferFlag = PLDM_START_AND_END;
}
else if (offset == 0)
{
transferFlag = PLDM_START;
}
else if (offset == applicableComponents.size() - 1)
{
transferFlag = PLDM_END;
}
else
{
transferFlag = PLDM_MIDDLE;
}
const auto& comp = compImageInfos[applicableComponents[offset]];
// ComponentClassification
CompClassification compClassification = std::get<static_cast<size_t>(
ComponentImageInfoPos::CompClassificationPos)>(comp);
// ComponentIdentifier
CompIdentifier compIdentifier =
std::get<static_cast<size_t>(ComponentImageInfoPos::CompIdentifierPos)>(
comp);
// ComponentClassificationIndex
CompClassificationIndex compClassificationIndex{};
auto compKey = std::make_pair(compClassification, compIdentifier);
if (compInfo.contains(compKey))
{
auto search = compInfo.find(compKey);
compClassificationIndex = search->second;
}
else
{
// Handle error scenario
}
// ComponentComparisonStamp
CompComparisonStamp compComparisonStamp = std::get<static_cast<size_t>(
ComponentImageInfoPos::CompComparisonStampPos)>(comp);
// ComponentVersionString
const auto& compVersion =
std::get<static_cast<size_t>(ComponentImageInfoPos::CompVersionPos)>(
comp);
variable_field compVerStrInfo{};
compVerStrInfo.ptr = reinterpret_cast<const uint8_t*>(compVersion.data());
compVerStrInfo.length = static_cast<uint8_t>(compVersion.size());
Request request(sizeof(pldm_msg_hdr) +
sizeof(struct pldm_pass_component_table_req) +
compVerStrInfo.length);
auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
auto rc = encode_pass_component_table_req(
instanceId, transferFlag, compClassification, compIdentifier,
compClassificationIndex, compComparisonStamp, PLDM_STR_TYPE_ASCII,
compVerStrInfo.length, &compVerStrInfo, requestMsg,
sizeof(pldm_pass_component_table_req) + compVerStrInfo.length);
if (rc)
{
updateManager->requester.markFree(eid, instanceId);
error("encode_pass_component_table_req failed, EID = {EID}, RC = {RC}",
"EID", unsigned(eid), "RC", rc);
// Handle error scenario
}
rc = updateManager->handler.registerRequest(
eid, instanceId, PLDM_FWUP, PLDM_PASS_COMPONENT_TABLE,
std::move(request),
std::move(std::bind_front(&DeviceUpdater::passCompTable, this)));
if (rc)
{
error(
"Failed to send PassComponentTable request, EID = {EID}, RC = {RC}",
"EID", unsigned(eid), "RC", rc);
// Handle error scenario
}
}
void DeviceUpdater::passCompTable(mctp_eid_t eid, const pldm_msg* response,
size_t respMsgLen)
{
if (response == nullptr || !respMsgLen)
{
// Handle error scenario
error("No response received for PassComponentTable, EID = {EID}", "EID",
unsigned(eid));
return;
}
uint8_t completionCode = 0;
uint8_t compResponse = 0;
uint8_t compResponseCode = 0;
auto rc = decode_pass_component_table_resp(response, respMsgLen,
&completionCode, &compResponse,
&compResponseCode);
if (rc)
{
// Handle error scenario
error(
"Decoding PassComponentTable response failed, EID={EID}, RC = {RC}",
"EID", unsigned(eid), "RC", rc);
return;
}
if (completionCode)
{
// Handle error scenario
error(
"PassComponentTable response failed with error completion code, EID = {EID}, CC = {CC}",
"EID", unsigned(eid), "CC", unsigned(completionCode));
return;
}
// Handle ComponentResponseCode
const auto& applicableComponents =
std::get<ApplicableComponents>(fwDeviceIDRecord);
if (componentIndex == applicableComponents.size() - 1)
{
componentIndex = 0;
pldmRequest = std::make_unique<sdeventplus::source::Defer>(
updateManager->event,
std::bind(&DeviceUpdater::sendUpdateComponentRequest, this,
componentIndex));
}
else
{
componentIndex++;
pldmRequest = std::make_unique<sdeventplus::source::Defer>(
updateManager->event,
std::bind(&DeviceUpdater::sendPassCompTableRequest, this,
componentIndex));
}
}
void DeviceUpdater::sendUpdateComponentRequest(size_t offset)
{
pldmRequest.reset();
auto instanceId = updateManager->requester.getInstanceId(eid);
const auto& applicableComponents =
std::get<ApplicableComponents>(fwDeviceIDRecord);
const auto& comp = compImageInfos[applicableComponents[offset]];
// ComponentClassification
CompClassification compClassification = std::get<static_cast<size_t>(
ComponentImageInfoPos::CompClassificationPos)>(comp);
// ComponentIdentifier
CompIdentifier compIdentifier =
std::get<static_cast<size_t>(ComponentImageInfoPos::CompIdentifierPos)>(
comp);
// ComponentClassificationIndex
CompClassificationIndex compClassificationIndex{};
auto compKey = std::make_pair(compClassification, compIdentifier);
if (compInfo.contains(compKey))
{
auto search = compInfo.find(compKey);
compClassificationIndex = search->second;
}
else
{
// Handle error scenario
}
// UpdateOptionFlags
bitfield32_t updateOptionFlags;
updateOptionFlags.bits.bit0 = std::get<3>(comp)[0];
// ComponentVersion
const auto& compVersion = std::get<7>(comp);
variable_field compVerStrInfo{};
compVerStrInfo.ptr = reinterpret_cast<const uint8_t*>(compVersion.data());
compVerStrInfo.length = static_cast<uint8_t>(compVersion.size());
Request request(sizeof(pldm_msg_hdr) +
sizeof(struct pldm_update_component_req) +
compVerStrInfo.length);
auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
auto rc = encode_update_component_req(
instanceId, compClassification, compIdentifier, compClassificationIndex,
std::get<static_cast<size_t>(
ComponentImageInfoPos::CompComparisonStampPos)>(comp),
std::get<static_cast<size_t>(ComponentImageInfoPos::CompSizePos)>(comp),
updateOptionFlags, PLDM_STR_TYPE_ASCII, compVerStrInfo.length,
&compVerStrInfo, requestMsg,
sizeof(pldm_update_component_req) + compVerStrInfo.length);
if (rc)
{
updateManager->requester.markFree(eid, instanceId);
error("encode_update_component_req failed, EID={EID}, RC = {RC}", "EID",
unsigned(eid), "RC", rc);
// Handle error scenario
}
rc = updateManager->handler.registerRequest(
eid, instanceId, PLDM_FWUP, PLDM_UPDATE_COMPONENT, std::move(request),
std::move(std::bind_front(&DeviceUpdater::updateComponent, this)));
if (rc)
{
error("Failed to send UpdateComponent request, EID={EID}, RC = {RC}",
"EID", unsigned(eid), "RC", rc);
// Handle error scenario
}
}
void DeviceUpdater::updateComponent(mctp_eid_t eid, const pldm_msg* response,
size_t respMsgLen)
{
if (response == nullptr || !respMsgLen)
{
// Handle error scenario
error("No response received for updateComponent, EID={EID}", "EID",
unsigned(eid));
return;
}
uint8_t completionCode = 0;
uint8_t compCompatibilityResp = 0;
uint8_t compCompatibilityRespCode = 0;
bitfield32_t updateOptionFlagsEnabled{};
uint16_t timeBeforeReqFWData = 0;
auto rc = decode_update_component_resp(
response, respMsgLen, &completionCode, &compCompatibilityResp,
&compCompatibilityRespCode, &updateOptionFlagsEnabled,
&timeBeforeReqFWData);
if (rc)
{
error("Decoding UpdateComponent response failed, EID={EID}, RC = {RC}",
"EID", unsigned(eid), "RC", rc);
return;
}
if (completionCode)
{
error(
"UpdateComponent response failed with error completion code, EID = {EID}, CC = {CC}",
"EID", unsigned(eid), "CC", unsigned(completionCode));
return;
}
}
Response DeviceUpdater::requestFwData(const pldm_msg* request,
size_t payloadLength)
{
uint8_t completionCode = PLDM_SUCCESS;
uint32_t offset = 0;
uint32_t length = 0;
Response response(sizeof(pldm_msg_hdr) + sizeof(completionCode), 0);
auto responseMsg = reinterpret_cast<pldm_msg*>(response.data());
auto rc = decode_request_firmware_data_req(request, payloadLength, &offset,
&length);
if (rc)
{
error(
"Decoding RequestFirmwareData request failed, EID={EID}, RC = {RC}",
"EID", unsigned(eid), "RC", rc);
rc = encode_request_firmware_data_resp(
request->hdr.instance_id, PLDM_ERROR_INVALID_DATA, responseMsg,
sizeof(completionCode));
if (rc)
{
error(
"Encoding RequestFirmwareData response failed, EID = {EID}, RC = {RC}",
"EID", unsigned(eid), "RC", rc);
}
return response;
}
const auto& applicableComponents =
std::get<ApplicableComponents>(fwDeviceIDRecord);
const auto& comp = compImageInfos[applicableComponents[componentIndex]];
auto compOffset = std::get<5>(comp);
auto compSize = std::get<6>(comp);
error("offset = {OFFSET}, length = {LEN}", "OFFSET", unsigned(offset),
"LEN", unsigned(length));
if (length < PLDM_FWUP_BASELINE_TRANSFER_SIZE || length > maxTransferSize)
{
rc = encode_request_firmware_data_resp(
request->hdr.instance_id, PLDM_FWUP_INVALID_TRANSFER_LENGTH,
responseMsg, sizeof(completionCode));
if (rc)
{
error(
"Encoding RequestFirmwareData response failed, EID={EID}, RC = {RC}",
"EID", unsigned(eid), "RC", rc);
}
return response;
}
if (offset + length > compSize + PLDM_FWUP_BASELINE_TRANSFER_SIZE)
{
rc = encode_request_firmware_data_resp(
request->hdr.instance_id, PLDM_FWUP_DATA_OUT_OF_RANGE, responseMsg,
sizeof(completionCode));
if (rc)
{
error(
"Encoding RequestFirmwareData response failed, EID={EID}, RC = {RC}",
"EID", unsigned(eid), "RC", rc);
}
return response;
}
size_t padBytes = 0;
if (offset + length > compSize)
{
padBytes = offset + length - compSize;
}
response.resize(sizeof(pldm_msg_hdr) + sizeof(completionCode) + length);
responseMsg = reinterpret_cast<pldm_msg*>(response.data());
package.seekg(compOffset + offset);
package.read(reinterpret_cast<char*>(response.data() +
sizeof(pldm_msg_hdr) +
sizeof(completionCode)),
length - padBytes);
rc = encode_request_firmware_data_resp(request->hdr.instance_id,
completionCode, responseMsg,
sizeof(completionCode));
if (rc)
{
error(
"Encoding RequestFirmwareData response failed, EID={EID}, RC = {RC}",
"EID", unsigned(eid), "RC", rc);
return response;
}
return response;
}
Response DeviceUpdater::transferComplete(const pldm_msg* request,
size_t payloadLength)
{
uint8_t completionCode = PLDM_SUCCESS;
Response response(sizeof(pldm_msg_hdr) + sizeof(completionCode), 0);
auto responseMsg = reinterpret_cast<pldm_msg*>(response.data());
uint8_t transferResult = 0;
auto rc = decode_transfer_complete_req(request, payloadLength,
&transferResult);
if (rc)
{
error("Decoding TransferComplete request failed, EID={EID}, RC = {RC}",
"EID", unsigned(eid), "RC", rc);
rc = encode_transfer_complete_resp(request->hdr.instance_id,
PLDM_ERROR_INVALID_DATA, responseMsg,
sizeof(completionCode));
if (rc)
{
error(
"Encoding TransferComplete response failed, EID={EID}, RC = {RC}",
"EID", unsigned(eid), "RC", rc);
}
return response;
}
const auto& applicableComponents =
std::get<ApplicableComponents>(fwDeviceIDRecord);
const auto& comp = compImageInfos[applicableComponents[componentIndex]];
const auto& compVersion = std::get<7>(comp);
if (transferResult == PLDM_FWUP_TRANSFER_SUCCESS)
{
info(
"Component Transfer complete, EID = {EID}, COMPONENT_VERSION = {COMP_VERS}",
"EID", unsigned(eid), "COMP_VERS", compVersion);
}
else
{
error(
"Transfer of the component failed, EID={EID}, COMPONENT_VERSION = {COMP_VERS}, TRANSFER_RESULT = {TRANS_RES}",
"EID", unsigned(eid), "COMP_VERS", compVersion, "TRANS_RES",
unsigned(transferResult));
}
rc = encode_transfer_complete_resp(request->hdr.instance_id, completionCode,
responseMsg, sizeof(completionCode));
if (rc)
{
error("Encoding TransferComplete response failed, EID={EID}, RC = {RC}",
"EID", unsigned(eid), "RC", rc);
return response;
}
return response;
}
Response DeviceUpdater::verifyComplete(const pldm_msg* request,
size_t payloadLength)
{
uint8_t completionCode = PLDM_SUCCESS;
Response response(sizeof(pldm_msg_hdr) + sizeof(completionCode), 0);
auto responseMsg = reinterpret_cast<pldm_msg*>(response.data());
uint8_t verifyResult = 0;
auto rc = decode_verify_complete_req(request, payloadLength, &verifyResult);
if (rc)
{
error("Decoding VerifyComplete request failed, EID = {EID}, RC = {RC}",
"EID", unsigned(eid), "RC", rc);
rc = encode_verify_complete_resp(request->hdr.instance_id,
PLDM_ERROR_INVALID_DATA, responseMsg,
sizeof(completionCode));
if (rc)
{
error(
"Encoding VerifyComplete response failed, EID={EID}, RC = {RC}",
"EID", unsigned(eid), "RC", rc);
}
return response;
}
const auto& applicableComponents =
std::get<ApplicableComponents>(fwDeviceIDRecord);
const auto& comp = compImageInfos[applicableComponents[componentIndex]];
const auto& compVersion = std::get<7>(comp);
if (verifyResult == PLDM_FWUP_VERIFY_SUCCESS)
{
info(
"Component verification complete, EID={EID}, COMPONENT_VERSION={COMP_VERS}",
"EID", unsigned(eid), "COMP_VERS", compVersion);
}
else
{
error(
"Component verification failed, EID={EID}, COMPONENT_VERSION={COMP_VERS}, VERIFY_RESULT={VERIFY_RES}",
"EID", unsigned(eid), "COMP_VERS", compVersion, "VERIFY_RES",
unsigned(verifyResult));
}
rc = encode_verify_complete_resp(request->hdr.instance_id, completionCode,
responseMsg, sizeof(completionCode));
if (rc)
{
error("Encoding VerifyComplete response failed, EID={EID}, RC = {RC}",
"EID", unsigned(eid), "RC", rc);
return response;
}
return response;
}
Response DeviceUpdater::applyComplete(const pldm_msg* request,
size_t payloadLength)
{
uint8_t completionCode = PLDM_SUCCESS;
Response response(sizeof(pldm_msg_hdr) + sizeof(completionCode), 0);
auto responseMsg = reinterpret_cast<pldm_msg*>(response.data());
uint8_t applyResult = 0;
bitfield16_t compActivationModification{};
auto rc = decode_apply_complete_req(request, payloadLength, &applyResult,
&compActivationModification);
if (rc)
{
error("Decoding ApplyComplete request failed, EID={EID}, RC = {RC}",
"EID", unsigned(eid), "RC", rc);
rc = encode_apply_complete_resp(request->hdr.instance_id,
PLDM_ERROR_INVALID_DATA, responseMsg,
sizeof(completionCode));
if (rc)
{
error(
"Encoding ApplyComplete response failed, EID={EID}, RC = {RC}",
"EID", unsigned(eid), "RC", rc);
}
return response;
}
const auto& applicableComponents =
std::get<ApplicableComponents>(fwDeviceIDRecord);
const auto& comp = compImageInfos[applicableComponents[componentIndex]];
const auto& compVersion = std::get<7>(comp);
if (applyResult == PLDM_FWUP_APPLY_SUCCESS ||
applyResult == PLDM_FWUP_APPLY_SUCCESS_WITH_ACTIVATION_METHOD)
{
info(
"Component apply complete, EID = {EID}, COMPONENT_VERSION = {COMP_VERS}",
"EID", unsigned(eid), "COMP_VERS", compVersion);
updateManager->updateActivationProgress();
}
else
{
error(
"Component apply failed, EID = {EID}, COMPONENT_VERSION = {COMP_VERS}, APPLY_RESULT = {APPLY_RES}",
"EID", unsigned(eid), "COMP_VERS", compVersion, "APPLY_RES",
unsigned(applyResult));
}
rc = encode_apply_complete_resp(request->hdr.instance_id, completionCode,
responseMsg, sizeof(completionCode));
if (rc)
{
error("Encoding ApplyComplete response failed, EID={EID}, RC = {RC}",
"EID", unsigned(eid), "RC", rc);
return response;
}
if (componentIndex == applicableComponents.size() - 1)
{
componentIndex = 0;
pldmRequest = std::make_unique<sdeventplus::source::Defer>(
updateManager->event,
std::bind(&DeviceUpdater::sendActivateFirmwareRequest, this));
}
else
{
componentIndex++;
pldmRequest = std::make_unique<sdeventplus::source::Defer>(
updateManager->event,
std::bind(&DeviceUpdater::sendUpdateComponentRequest, this,
componentIndex));
}
return response;
}
void DeviceUpdater::sendActivateFirmwareRequest()
{
pldmRequest.reset();
auto instanceId = updateManager->requester.getInstanceId(eid);
Request request(sizeof(pldm_msg_hdr) +
sizeof(struct pldm_activate_firmware_req));
auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
auto rc = encode_activate_firmware_req(
instanceId, PLDM_NOT_ACTIVATE_SELF_CONTAINED_COMPONENTS, requestMsg,
sizeof(pldm_activate_firmware_req));
if (rc)
{
updateManager->requester.markFree(eid, instanceId);
error("encode_activate_firmware_req failed, EID={EID}, RC = {RC}",
"EID", unsigned(eid), "RC", rc);
}
rc = updateManager->handler.registerRequest(
eid, instanceId, PLDM_FWUP, PLDM_ACTIVATE_FIRMWARE, std::move(request),
std::move(std::bind_front(&DeviceUpdater::activateFirmware, this)));
if (rc)
{
error("Failed to send ActivateFirmware request, EID={EID}, RC = {RC}",
"EID", unsigned(eid), "RC", rc);
}
}
void DeviceUpdater::activateFirmware(mctp_eid_t eid, const pldm_msg* response,
size_t respMsgLen)
{
if (response == nullptr || !respMsgLen)
{
// Handle error scenario
error("No response received for ActivateFirmware, EID={EID}", "EID",
unsigned(eid));
return;
}
uint8_t completionCode = 0;
uint16_t estimatedTimeForActivation = 0;
auto rc = decode_activate_firmware_resp(
response, respMsgLen, &completionCode, &estimatedTimeForActivation);
if (rc)
{
// Handle error scenario
error("Decoding ActivateFirmware response failed, EID={EID}, RC = {RC}",
"EID", unsigned(eid), "RC", rc);
return;
}
if (completionCode)
{
// Handle error scenario
error(
"ActivateFirmware response failed with error completion code, EID = {EID}, CC = {CC}",
"EID", unsigned(eid), "CC", unsigned(completionCode));
return;
}
updateManager->updateDeviceCompletion(eid, true);
}
} // namespace fw_update
} // namespace pldm