blob: 49c9b1e1d888c3cc3bc3afd010cfe030d51acef3 [file] [log] [blame]
Alexander Hansen0119cd72025-01-14 14:15:39 +01001#include "device.hpp"
2
3#include "common/pldm/pldm_package_util.hpp"
4#include "software.hpp"
5#include "software_manager.hpp"
6
7#include <phosphor-logging/lg2.hpp>
8#include <sdbusplus/asio/object_server.hpp>
9#include <sdbusplus/async/context.hpp>
10#include <sdbusplus/bus.hpp>
11#include <xyz/openbmc_project/Association/Definitions/server.hpp>
12#include <xyz/openbmc_project/State/Host/client.hpp>
13
14#include <utility>
15
16const auto applyTimeImmediate = sdbusplus::common::xyz::openbmc_project::
17 software::ApplyTime::RequestedApplyTimes::Immediate;
18
19Device::Device(sdbusplus::async::context& ctx, bool isDryRun,
20 const DeviceConfig& config, SoftwareManager* parent) :
21 config(config), parent(parent), dryRun(isDryRun), ctx(ctx)
22{}
23
24// NOLINTBEGIN
25sdbusplus::async::task<bool> Device::startUpdateAsync(
26 sdbusplus::message::unix_fd image, RequestedApplyTimes applyTime,
27 std::unique_ptr<Software> softwareUpdate)
28// NOLINTEND
29{
30 lg2::debug("starting the async update with memfd {FD}", "FD", image.fd);
31
32 size_t pldm_pkg_size;
33
34 void* pldm_pkg = pldm_package_util::mmapImagePackage(image, &pldm_pkg_size);
35
36 if (pldm_pkg == NULL)
37 {
38 co_return false;
39 }
40
41 lg2::debug("[Device] mmapped the pldm update package");
42
43 std::shared_ptr<PackageParser> pp = pldm_package_util::parsePLDMPackage(
44 static_cast<uint8_t*>(pldm_pkg), pldm_pkg_size);
45
46 if (pp == nullptr)
47 {
48 lg2::error("could not parse PLDM package");
49 co_return false;
50 }
51
52 const bool success = co_await continueUpdateWithMappedPackage(
53 pldm_pkg, pp, applyTime, softwareUpdate);
54
55 if (success)
56 {
57 lg2::info("deleting old sw version {SWID}", "SWID",
58 this->softwareCurrent->swid);
59
60 this->softwareCurrent = std::move(softwareUpdate);
61
62 lg2::info("new current sw version: {SWID}", "SWID",
63 this->softwareCurrent->swid);
64 }
65 else
66 {
67 lg2::info("update failed, deleting sw update version {SWID}", "SWID",
68 softwareUpdate->swid);
69 }
70
71 softwareUpdate = nullptr;
72
73 if (munmap(pldm_pkg, pldm_pkg_size) != 0)
74 {
75 lg2::error("[Device] failed to munmap the pldm package");
76 }
77
78 if (close(image.fd) != 0)
79 {
80 lg2::error("[Device] failed to close file descriptor {FD}", "FD",
81 image.fd);
82 }
83
84 co_return success;
85}
86
87std::string Device::getEMConfigType() const
88{
89 return this->config.configType;
90}
91
92void Device::resetDevice()
93{
94 lg2::info("[Device] default implementation for reset device (nop)");
95}
96
97std::set<RequestedApplyTimes> Device::allowedApplyTimes()
98{
99 return {RequestedApplyTimes::Immediate, RequestedApplyTimes::OnReset};
100}
101
102// NOLINTBEGIN
103sdbusplus::async::task<bool> Device::continueUpdateWithMappedPackage(
104 void* pldm_pkg, const std::shared_ptr<PackageParser>& packageParser,
105 sdbusplus::common::xyz::openbmc_project::software::ApplyTime::
106 RequestedApplyTimes applyTime,
107 const std::unique_ptr<Software>& softwareUpdate)
108// NOLINTEND
109{
110 int status = 0;
111
112 // extract the component image for the specific device
113 size_t matchingComponentImageSize;
114 uint32_t matchingComponentOffset;
115 status = pldm_package_util::extractMatchingComponentImage(
116 packageParser, config.compatibleHardware, config.vendorIANA,
117 &matchingComponentOffset, &matchingComponentImageSize);
118
119 if (status != 0)
120 {
121 lg2::error("could not extract matching component image");
122
123 softwareUpdate->setActivation(
124 ActivationInterface::Activations::Invalid);
125
126 co_return false;
127 }
128
129 const uint8_t* matchingComponentImage =
130 static_cast<uint8_t*>(pldm_pkg) + matchingComponentOffset;
131
132 softwareUpdate->setActivation(ActivationInterface::Activations::Ready);
133
134 softwareUpdate->setVersion(packageParser->pkgVersion);
135
136 std::string objPath = softwareUpdate->getObjectPath();
137
138 softwareUpdate->optSoftwareActivationProgress =
139 std::make_unique<SoftwareActivationProgress>(ctx, objPath.c_str());
140
141 softwareUpdate->setActivationBlocksTransition(true);
142
143 softwareUpdate->setActivation(ActivationInterface::Activations::Activating);
144
145 bool success = co_await updateDevice(
146 matchingComponentImage, matchingComponentImageSize,
147 softwareUpdate->optSoftwareActivationProgress);
148
149 if (success)
150 {
151 softwareUpdate->setActivation(ActivationInterface::Activations::Active);
152 }
153
154 softwareUpdate->setActivationBlocksTransition(false);
155
156 softwareUpdate->optSoftwareActivationProgress = nullptr;
157
158 if (!success)
159 {
160 // do not apply the update, it has failed.
161 // We can delete the new software version.
162
163 co_return false;
164 }
165
166 if (applyTime == applyTimeImmediate)
167 {
168 this->resetDevice();
169
170 co_await softwareUpdate->setAssociationDefinitionsRunningActivating(
171 true, false);
172
173 softwareUpdate->enableUpdate(this->allowedApplyTimes());
174 }
175 else
176 {
177 co_await softwareUpdate->setAssociationDefinitionsRunningActivating(
178 false, true);
179 }
180
181 co_return true;
182}