#include "device_updater.hpp" #include "activation.hpp" #include "update_manager.hpp" #include #include #include PHOSPHOR_LOG2_USING; namespace pldm { namespace fw_update { void DeviceUpdater::startFwUpdateFlow() { auto instanceId = updateManager->instanceIdDb.next(eid); // NumberOfComponents const auto& applicableComponents = std::get(fwDeviceIDRecord); // PackageDataLength const auto& fwDevicePkgData = std::get(fwDeviceIDRecord); // ComponentImageSetVersionString const auto& compImageSetVersion = std::get(fwDeviceIDRecord); variable_field compImgSetVerStrInfo{}; compImgSetVerStrInfo.ptr = reinterpret_cast(compImageSetVersion.data()); compImgSetVerStrInfo.length = static_cast(compImageSetVersion.size()); Request request(sizeof(pldm_msg_hdr) + sizeof(struct pldm_request_update_req) + compImgSetVerStrInfo.length); auto requestMsg = reinterpret_cast(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) { // Handle error scenario updateManager->instanceIdDb.free(eid, instanceId); error( "Failed to encode request update request for endpoint ID '{EID}', response code '{RC}'", "EID", eid, "RC", rc); } rc = updateManager->handler.registerRequest( eid, instanceId, PLDM_FWUP, PLDM_REQUEST_UPDATE, std::move(request), std::move(std::bind_front(&DeviceUpdater::requestUpdate, this))); if (rc) { // Handle error scenario error( "Failed to send request update for endpoint ID '{EID}', response code '{RC}'", "EID", eid, "RC", rc); } } 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 request update for endpoint ID '{EID}'", "EID", 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( "Failed to decode request update response for endpoint ID '{EID}', response code '{RC}'", "EID", eid, "RC", rc); return; } if (completionCode) { error( "Failure in request update response for endpoint ID '{EID}', completion code '{CC}'", "EID", eid, "CC", completionCode); return; } // Optional fields DeviceMetaData and GetPackageData not handled pldmRequest = std::make_unique( updateManager->event, std::bind(&DeviceUpdater::sendPassCompTableRequest, this, componentIndex)); } void DeviceUpdater::sendPassCompTableRequest(size_t offset) { pldmRequest.reset(); auto instanceId = updateManager->instanceIdDb.next(eid); // TransferFlag const auto& applicableComponents = std::get(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( ComponentImageInfoPos::CompClassificationPos)>(comp); // ComponentIdentifier CompIdentifier compIdentifier = std::get(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 error( "Failed to find component classification '{CLASSIFICATION}' and identifier '{IDENTIFIER}'", "CLASSIFICATION", compClassification, "IDENTIFIER", compIdentifier); } // ComponentComparisonStamp CompComparisonStamp compComparisonStamp = std::get( ComponentImageInfoPos::CompComparisonStampPos)>(comp); // ComponentVersionString const auto& compVersion = std::get(ComponentImageInfoPos::CompVersionPos)>( comp); variable_field compVerStrInfo{}; compVerStrInfo.ptr = reinterpret_cast(compVersion.data()); compVerStrInfo.length = static_cast(compVersion.size()); Request request(sizeof(pldm_msg_hdr) + sizeof(struct pldm_pass_component_table_req) + compVerStrInfo.length); auto requestMsg = reinterpret_cast(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) { // Handle error scenario updateManager->instanceIdDb.free(eid, instanceId); error( "Failed to encode pass component table req for endpoint ID '{EID}', response code '{RC}'", "EID", eid, "RC", rc); } 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) { // Handle error scenario error( "Failed to send pass component table request for endpoint ID '{EID}', response code '{RC}'", "EID", eid, "RC", rc); } } 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 pass component table for endpoint ID '{EID}'", "EID", 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( "Failed to decode pass component table response for endpoint ID '{EID}', response code '{RC}'", "EID", eid, "RC", rc); return; } if (completionCode) { // Handle error scenario error( "Failed to pass component table response for endpoint ID '{EID}', completion code '{CC}'", "EID", eid, "CC", completionCode); return; } // Handle ComponentResponseCode const auto& applicableComponents = std::get(fwDeviceIDRecord); if (componentIndex == applicableComponents.size() - 1) { componentIndex = 0; pldmRequest = std::make_unique( updateManager->event, std::bind(&DeviceUpdater::sendUpdateComponentRequest, this, componentIndex)); } else { componentIndex++; pldmRequest = std::make_unique( updateManager->event, std::bind(&DeviceUpdater::sendPassCompTableRequest, this, componentIndex)); } } void DeviceUpdater::sendUpdateComponentRequest(size_t offset) { pldmRequest.reset(); auto instanceId = updateManager->instanceIdDb.next(eid); const auto& applicableComponents = std::get(fwDeviceIDRecord); const auto& comp = compImageInfos[applicableComponents[offset]]; // ComponentClassification CompClassification compClassification = std::get( ComponentImageInfoPos::CompClassificationPos)>(comp); // ComponentIdentifier CompIdentifier compIdentifier = std::get(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 error( "Failed to find component classification '{CLASSIFICATION}' and identifier '{IDENTIFIER}'", "CLASSIFICATION", compClassification, "IDENTIFIER", compIdentifier); } // 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(compVersion.data()); compVerStrInfo.length = static_cast(compVersion.size()); Request request(sizeof(pldm_msg_hdr) + sizeof(struct pldm_update_component_req) + compVerStrInfo.length); auto requestMsg = reinterpret_cast(request.data()); auto rc = encode_update_component_req( instanceId, compClassification, compIdentifier, compClassificationIndex, std::get( ComponentImageInfoPos::CompComparisonStampPos)>(comp), std::get(ComponentImageInfoPos::CompSizePos)>(comp), updateOptionFlags, PLDM_STR_TYPE_ASCII, compVerStrInfo.length, &compVerStrInfo, requestMsg, sizeof(pldm_update_component_req) + compVerStrInfo.length); if (rc) { // Handle error scenario updateManager->instanceIdDb.free(eid, instanceId); error( "Failed to encode update component req for endpoint ID '{EID}', response code '{RC}'", "EID", eid, "RC", rc); } rc = updateManager->handler.registerRequest( eid, instanceId, PLDM_FWUP, PLDM_UPDATE_COMPONENT, std::move(request), std::move(std::bind_front(&DeviceUpdater::updateComponent, this))); if (rc) { // Handle error scenario error( "Failed to send update request for endpoint ID '{EID}', response code '{RC}'", "EID", eid, "RC", rc); } } 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 update component with endpoint ID {EID}", "EID", 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( "Failed to decode update request response for endpoint ID '{EID}', response code '{RC}'", "EID", eid, "RC", rc); return; } if (completionCode) { error( "Failed to update request response for endpoint ID '{EID}', completion code '{CC}'", "EID", eid, "CC", 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(response.data()); auto rc = decode_request_firmware_data_req(request, payloadLength, &offset, &length); if (rc) { error( "Failed to decode request firmware date request for endpoint ID '{EID}', response code '{RC}'", "EID", eid, "RC", rc); rc = encode_request_firmware_data_resp( request->hdr.instance_id, PLDM_ERROR_INVALID_DATA, responseMsg, sizeof(completionCode)); if (rc) { error( "Failed to encode request firmware date response for endpoint ID '{EID}', response code '{RC}'", "EID", eid, "RC", rc); } return response; } const auto& applicableComponents = std::get(fwDeviceIDRecord); const auto& comp = compImageInfos[applicableComponents[componentIndex]]; auto compOffset = std::get<5>(comp); auto compSize = std::get<6>(comp); info("Decoded fw request data at offset '{OFFSET}' and length '{LENGTH}' ", "OFFSET", offset, "LENGTH", 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( "Failed to encode request firmware date response for endpoint ID '{EID}', response code '{RC}'", "EID", 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( "Failed to encode request firmware date response for endpoint ID '{EID}', response code '{RC}'", "EID", 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(response.data()); package.seekg(compOffset + offset); package.read(reinterpret_cast(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( "Failed to encode request firmware date response for endpoint ID '{EID}', response code '{RC}'", "EID", 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(response.data()); uint8_t transferResult = 0; auto rc = decode_transfer_complete_req(request, payloadLength, &transferResult); if (rc) { error( "Failed to decode TransferComplete request for endpoint ID '{EID}', response code '{RC}'", "EID", eid, "RC", rc); rc = encode_transfer_complete_resp(request->hdr.instance_id, PLDM_ERROR_INVALID_DATA, responseMsg, sizeof(completionCode)); if (rc) { error( "Failed to encode TransferComplete response for endpoint ID '{EID}', response code '{RC}'", "EID", eid, "RC", rc); } return response; } const auto& applicableComponents = std::get(fwDeviceIDRecord); const auto& comp = compImageInfos[applicableComponents[componentIndex]]; const auto& compVersion = std::get<7>(comp); if (transferResult == PLDM_FWUP_TRANSFER_SUCCESS) { info( "Component endpoint ID '{EID}' and version '{COMPONENT_VERSION}' transfer complete.", "EID", eid, "COMPONENT_VERSION", compVersion); } else { error( "Failure in transfer of the component endpoint ID '{EID}' and version '{COMPONENT_VERSION}' with transfer result - {RESULT}", "EID", eid, "COMPONENT_VERSION", compVersion, "RESULT", transferResult); } rc = encode_transfer_complete_resp(request->hdr.instance_id, completionCode, responseMsg, sizeof(completionCode)); if (rc) { error( "Failed to encode transfer complete response of endpoint ID '{EID}', response code '{RC}'", "EID", 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(response.data()); uint8_t verifyResult = 0; auto rc = decode_verify_complete_req(request, payloadLength, &verifyResult); if (rc) { error( "Failed to decode verify complete request of endpoint ID '{EID}', response code '{RC}'", "EID", eid, "RC", rc); rc = encode_verify_complete_resp(request->hdr.instance_id, PLDM_ERROR_INVALID_DATA, responseMsg, sizeof(completionCode)); if (rc) { error( "Failed to encode verify complete response of endpoint ID '{EID}', response code '{RC}'.", "EID", eid, "RC", rc); } return response; } const auto& applicableComponents = std::get(fwDeviceIDRecord); const auto& comp = compImageInfos[applicableComponents[componentIndex]]; const auto& compVersion = std::get<7>(comp); if (verifyResult == PLDM_FWUP_VERIFY_SUCCESS) { info( "Component endpoint ID '{EID}' and version '{COMPONENT_VERSION}' verification complete.", "EID", eid, "COMPONENT_VERSION", compVersion); } else { error( "Failed to verify component endpoint ID '{EID}' and version '{COMPONENT_VERSION}' with transfer result - '{RESULT}'", "EID", eid, "COMPONENT_VERSION", compVersion, "RESULT", verifyResult); } rc = encode_verify_complete_resp(request->hdr.instance_id, completionCode, responseMsg, sizeof(completionCode)); if (rc) { error( "Failed to encode verify complete response for endpoint ID '{EID}', response code - {RC}", "EID", 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(response.data()); uint8_t applyResult = 0; bitfield16_t compActivationModification{}; auto rc = decode_apply_complete_req(request, payloadLength, &applyResult, &compActivationModification); if (rc) { error( "Failed to decode apply complete request for endpoint ID '{EID}', response code '{RC}'", "EID", eid, "RC", rc); rc = encode_apply_complete_resp(request->hdr.instance_id, PLDM_ERROR_INVALID_DATA, responseMsg, sizeof(completionCode)); if (rc) { error( "Failed to encode apply complete response for endpoint ID '{EID}', response code '{RC}'", "EID", eid, "RC", rc); } return response; } const auto& applicableComponents = std::get(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 endpoint ID '{EID}' with '{COMPONENT_VERSION}' apply complete.", "EID", eid, "COMPONENT_VERSION", compVersion); updateManager->updateActivationProgress(); } else { error( "Failed to apply component endpoint ID '{EID}' and version '{COMPONENT_VERSION}', error - {ERROR}", "EID", eid, "COMPONENT_VERSION", compVersion, "ERROR", applyResult); } rc = encode_apply_complete_resp(request->hdr.instance_id, completionCode, responseMsg, sizeof(completionCode)); if (rc) { error( "Failed to encode apply complete response for endpoint ID '{EID}', response code '{RC}'", "EID", eid, "RC", rc); return response; } if (componentIndex == applicableComponents.size() - 1) { componentIndex = 0; pldmRequest = std::make_unique( updateManager->event, std::bind(&DeviceUpdater::sendActivateFirmwareRequest, this)); } else { componentIndex++; pldmRequest = std::make_unique( updateManager->event, std::bind(&DeviceUpdater::sendUpdateComponentRequest, this, componentIndex)); } return response; } void DeviceUpdater::sendActivateFirmwareRequest() { pldmRequest.reset(); auto instanceId = updateManager->instanceIdDb.next(eid); Request request(sizeof(pldm_msg_hdr) + sizeof(struct pldm_activate_firmware_req)); auto requestMsg = reinterpret_cast(request.data()); auto rc = encode_activate_firmware_req( instanceId, PLDM_NOT_ACTIVATE_SELF_CONTAINED_COMPONENTS, requestMsg, sizeof(pldm_activate_firmware_req)); if (rc) { updateManager->instanceIdDb.free(eid, instanceId); error( "Failed to encode activate firmware req for endpoint ID '{EID}', response code '{RC}'", "EID", 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 activate firmware request for endpoint ID '{EID}', response code '{RC}'", "EID", 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 activate firmware for endpoint ID '{EID}'", "EID", 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( "Failed to decode activate firmware response for endpoint ID '{EID}', response code '{RC}'", "EID", eid, "RC", rc); return; } if (completionCode) { // Handle error scenario error( "Failed to activate firmware response for endpoint ID '{EID}', completion code '{CC}'", "EID", eid, "CC", completionCode); return; } updateManager->updateDeviceCompletion(eid, true); } } // namespace fw_update } // namespace pldm