blob: 49c9b1e1d888c3cc3bc3afd010cfe030d51acef3 [file] [log] [blame]
#include "device.hpp"
#include "common/pldm/pldm_package_util.hpp"
#include "software.hpp"
#include "software_manager.hpp"
#include <phosphor-logging/lg2.hpp>
#include <sdbusplus/asio/object_server.hpp>
#include <sdbusplus/async/context.hpp>
#include <sdbusplus/bus.hpp>
#include <xyz/openbmc_project/Association/Definitions/server.hpp>
#include <xyz/openbmc_project/State/Host/client.hpp>
#include <utility>
const auto applyTimeImmediate = sdbusplus::common::xyz::openbmc_project::
software::ApplyTime::RequestedApplyTimes::Immediate;
Device::Device(sdbusplus::async::context& ctx, bool isDryRun,
const DeviceConfig& config, SoftwareManager* parent) :
config(config), parent(parent), dryRun(isDryRun), ctx(ctx)
{}
// NOLINTBEGIN
sdbusplus::async::task<bool> Device::startUpdateAsync(
sdbusplus::message::unix_fd image, RequestedApplyTimes applyTime,
std::unique_ptr<Software> softwareUpdate)
// NOLINTEND
{
lg2::debug("starting the async update with memfd {FD}", "FD", image.fd);
size_t pldm_pkg_size;
void* pldm_pkg = pldm_package_util::mmapImagePackage(image, &pldm_pkg_size);
if (pldm_pkg == NULL)
{
co_return false;
}
lg2::debug("[Device] mmapped the pldm update package");
std::shared_ptr<PackageParser> pp = pldm_package_util::parsePLDMPackage(
static_cast<uint8_t*>(pldm_pkg), pldm_pkg_size);
if (pp == nullptr)
{
lg2::error("could not parse PLDM package");
co_return false;
}
const bool success = co_await continueUpdateWithMappedPackage(
pldm_pkg, pp, applyTime, softwareUpdate);
if (success)
{
lg2::info("deleting old sw version {SWID}", "SWID",
this->softwareCurrent->swid);
this->softwareCurrent = std::move(softwareUpdate);
lg2::info("new current sw version: {SWID}", "SWID",
this->softwareCurrent->swid);
}
else
{
lg2::info("update failed, deleting sw update version {SWID}", "SWID",
softwareUpdate->swid);
}
softwareUpdate = nullptr;
if (munmap(pldm_pkg, pldm_pkg_size) != 0)
{
lg2::error("[Device] failed to munmap the pldm package");
}
if (close(image.fd) != 0)
{
lg2::error("[Device] failed to close file descriptor {FD}", "FD",
image.fd);
}
co_return success;
}
std::string Device::getEMConfigType() const
{
return this->config.configType;
}
void Device::resetDevice()
{
lg2::info("[Device] default implementation for reset device (nop)");
}
std::set<RequestedApplyTimes> Device::allowedApplyTimes()
{
return {RequestedApplyTimes::Immediate, RequestedApplyTimes::OnReset};
}
// NOLINTBEGIN
sdbusplus::async::task<bool> Device::continueUpdateWithMappedPackage(
void* pldm_pkg, const std::shared_ptr<PackageParser>& packageParser,
sdbusplus::common::xyz::openbmc_project::software::ApplyTime::
RequestedApplyTimes applyTime,
const std::unique_ptr<Software>& softwareUpdate)
// NOLINTEND
{
int status = 0;
// extract the component image for the specific device
size_t matchingComponentImageSize;
uint32_t matchingComponentOffset;
status = pldm_package_util::extractMatchingComponentImage(
packageParser, config.compatibleHardware, config.vendorIANA,
&matchingComponentOffset, &matchingComponentImageSize);
if (status != 0)
{
lg2::error("could not extract matching component image");
softwareUpdate->setActivation(
ActivationInterface::Activations::Invalid);
co_return false;
}
const uint8_t* matchingComponentImage =
static_cast<uint8_t*>(pldm_pkg) + matchingComponentOffset;
softwareUpdate->setActivation(ActivationInterface::Activations::Ready);
softwareUpdate->setVersion(packageParser->pkgVersion);
std::string objPath = softwareUpdate->getObjectPath();
softwareUpdate->optSoftwareActivationProgress =
std::make_unique<SoftwareActivationProgress>(ctx, objPath.c_str());
softwareUpdate->setActivationBlocksTransition(true);
softwareUpdate->setActivation(ActivationInterface::Activations::Activating);
bool success = co_await updateDevice(
matchingComponentImage, matchingComponentImageSize,
softwareUpdate->optSoftwareActivationProgress);
if (success)
{
softwareUpdate->setActivation(ActivationInterface::Activations::Active);
}
softwareUpdate->setActivationBlocksTransition(false);
softwareUpdate->optSoftwareActivationProgress = nullptr;
if (!success)
{
// do not apply the update, it has failed.
// We can delete the new software version.
co_return false;
}
if (applyTime == applyTimeImmediate)
{
this->resetDevice();
co_await softwareUpdate->setAssociationDefinitionsRunningActivating(
true, false);
softwareUpdate->enableUpdate(this->allowedApplyTimes());
}
else
{
co_await softwareUpdate->setAssociationDefinitionsRunningActivating(
false, true);
}
co_return true;
}