#include "device.hpp" #include "common/pldm/pldm_package_util.hpp" #include "software.hpp" #include "software_manager.hpp" #include #include #include #include #include #include #include #include PHOSPHOR_LOG2_USING; using namespace phosphor::software::device; using SoftwareActivationProgress = sdbusplus::aserver::xyz::openbmc_project::software::ActivationProgress< phosphor::software::Software>; using SoftwareActivationProgressProperties = sdbusplus::common::xyz:: openbmc_project::software::ActivationProgress::properties_t; const auto applyTimeImmediate = sdbusplus::common::xyz::openbmc_project:: software::ApplyTime::RequestedApplyTimes::Immediate; const auto ActivationInvalid = ActivationInterface::Activations::Invalid; const auto ActivationFailed = ActivationInterface::Activations::Failed; Device::Device(sdbusplus::async::context& ctx, const SoftwareConfig& config, manager::SoftwareManager* parent, std::set allowedApplyTimes = {RequestedApplyTimes::Immediate, RequestedApplyTimes::OnReset}) : allowedApplyTimes(std::move(allowedApplyTimes)), config(config), parent(parent), ctx(ctx) {} sdbusplus::async::task Device::getImageInfo( std::unique_ptr>& pldmPackage, size_t pldmPackageSize, uint8_t** matchingComponentImage, size_t* componentImageSize, std::string& componentVersion) { std::shared_ptr packageParser = pldm_package_util::parsePLDMPackage( static_cast(pldmPackage.get()), pldmPackageSize); if (packageParser == nullptr) { error("could not parse PLDM package"); co_return false; } uint32_t componentOffset = 0; const int status = pldm_package_util::extractMatchingComponentImage( packageParser, config.compatibleHardware, config.vendorIANA, &componentOffset, componentImageSize, componentVersion); if (status != 0) { error("could not extract matching component image"); co_return false; } *matchingComponentImage = static_cast(pldmPackage.get()) + componentOffset; co_return true; } sdbusplus::async::task Device::startUpdateAsync( sdbusplus::message::unix_fd image, RequestedApplyTimes applyTime, std::unique_ptr softwarePendingIn) { debug("starting the async update with memfd {FD}", "FD", image.fd); size_t pldm_pkg_size = 0; auto pldm_pkg = pldm_package_util::mmapImagePackage(image, &pldm_pkg_size); if (pldm_pkg == nullptr) { softwarePendingIn->setActivation(ActivationInvalid); co_return false; } uint8_t* componentImage; size_t componentImageSize = 0; std::string componentVersion; if (!co_await getImageInfo(pldm_pkg, pldm_pkg_size, &componentImage, &componentImageSize, componentVersion)) { error("could not extract matching component image"); softwarePendingIn->setActivation(ActivationInvalid); co_return false; } std::unique_ptr softwarePendingOld = std::move(softwarePending); softwarePending = std::move(softwarePendingIn); softwarePendingIn = nullptr; const bool success = co_await continueUpdateWithMappedPackage( componentImage, componentImageSize, componentVersion, applyTime); if (!success) { softwarePending->setActivation(ActivationFailed); error("Failed to update the software for {SWID}", "SWID", softwareCurrent->swid); softwarePending = std::move(softwarePendingOld); co_return false; } if (applyTime == RequestedApplyTimes::Immediate) { softwareCurrent = std::move(softwarePending); // In case an immediate update is triggered after an update for // onReset. softwarePending = nullptr; debug("Successfully updated to software version {SWID}", "SWID", softwareCurrent->swid); } co_return true; } std::string Device::getEMConfigType() const { return config.configType; } sdbusplus::async::task Device::resetDevice() { debug("Default implementation for device reset"); co_return true; } bool Device::setUpdateProgress(uint8_t progress) const { if (!softwarePending || !softwarePending->softwareActivationProgress) { return false; } softwarePending->softwareActivationProgress->progress(progress); return true; } sdbusplus::async::task Device::continueUpdateWithMappedPackage( const uint8_t* matchingComponentImage, size_t componentImageSize, const std::string& componentVersion, RequestedApplyTimes applyTime) { softwarePending->setActivation(ActivationInterface::Activations::Ready); softwarePending->setVersion(componentVersion, softwareCurrent->getPurpose().value_or( SoftwareVersion::VersionPurpose::Unknown)); std::string objPath = softwarePending->objectPath; softwarePending->softwareActivationProgress = std::make_unique( ctx, objPath.c_str(), SoftwareActivationProgressProperties{0}); softwarePending->softwareActivationProgress->emit_added(); softwarePending->setActivationBlocksTransition(true); softwarePending->setActivation( ActivationInterface::Activations::Activating); bool success = co_await updateDevice(matchingComponentImage, componentImageSize); if (success) { softwarePending->setActivation( ActivationInterface::Activations::Active); } softwarePending->setActivationBlocksTransition(false); softwarePending->softwareActivationProgress = nullptr; if (!success) { // do not apply the update, it has failed. // We can delete the new software version. co_return false; } if (applyTime == applyTimeImmediate) { co_await resetDevice(); co_await softwarePending->createInventoryAssociations(true); softwarePending->enableUpdate(allowedApplyTimes); } else { co_await softwarePending->createInventoryAssociations(false); } co_return true; }