blob: 471697c61da5f7470feeeae9159e6291f94e8ec4 [file] [log] [blame]
Alexander Hansencc372352025-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
16PHOSPHOR_LOG2_USING;
17
18using namespace phosphor::software::device;
19
20const auto applyTimeImmediate = sdbusplus::common::xyz::openbmc_project::
21 software::ApplyTime::RequestedApplyTimes::Immediate;
22
23const auto ActivationInvalid = ActivationInterface::Activations::Invalid;
24const auto ActivationFailed = ActivationInterface::Activations::Failed;
25
26Device::Device(sdbusplus::async::context& ctx, const SoftwareConfig& config,
27 manager::SoftwareManager* parent,
28 std::set<RequestedApplyTimes> allowedApplyTimes =
29 {RequestedApplyTimes::Immediate,
30 RequestedApplyTimes::OnReset}) :
31 allowedApplyTimes(std::move(allowedApplyTimes)), config(config),
32 parent(parent), ctx(ctx)
33{}
34
35// NOLINTBEGIN(readability-static-accessed-through-instance)
36sdbusplus::async::task<bool> Device::getImageInfo(
37 std::unique_ptr<void, std::function<void(void*)>>& pldmPackage,
38 size_t pldmPackageSize, uint8_t** matchingComponentImage,
39 size_t* componentImageSize, std::string& componentVersion)
40
41// NOLINTEND(readability-static-accessed-through-instance)
42{
43 std::shared_ptr<PackageParser> packageParser =
44 pldm_package_util::parsePLDMPackage(
45 static_cast<uint8_t*>(pldmPackage.get()), pldmPackageSize);
46
47 if (packageParser == nullptr)
48 {
49 error("could not parse PLDM package");
50 co_return false;
51 }
52
53 uint32_t componentOffset = 0;
54 const int status = pldm_package_util::extractMatchingComponentImage(
55 packageParser, config.compatibleHardware, config.vendorIANA,
56 &componentOffset, componentImageSize, componentVersion);
57
58 if (status != 0)
59 {
60 error("could not extract matching component image");
61 co_return false;
62 }
63
64 *matchingComponentImage =
65 static_cast<uint8_t*>(pldmPackage.get()) + componentOffset;
66
67 co_return true;
68}
69
70// NOLINTBEGIN(readability-static-accessed-through-instance)
71sdbusplus::async::task<bool> Device::startUpdateAsync(
72 sdbusplus::message::unix_fd image, RequestedApplyTimes applyTime,
73 std::unique_ptr<Software> softwarePendingIn)
74// NOLINTEND(readability-static-accessed-through-instance)
75{
76 debug("starting the async update with memfd {FD}", "FD", image.fd);
77
78 size_t pldm_pkg_size = 0;
79 auto pldm_pkg = pldm_package_util::mmapImagePackage(image, &pldm_pkg_size);
80
81 if (pldm_pkg == nullptr)
82 {
83 softwarePendingIn->setActivation(ActivationInvalid);
84 co_return false;
85 }
86
87 uint8_t* componentImage;
88 size_t componentImageSize = 0;
89 std::string componentVersion;
90
91 if (!co_await getImageInfo(pldm_pkg, pldm_pkg_size, &componentImage,
92 &componentImageSize, componentVersion))
93 {
94 error("could not extract matching component image");
95 softwarePendingIn->setActivation(ActivationInvalid);
96 co_return false;
97 }
98
99 const bool success = co_await continueUpdateWithMappedPackage(
100 componentImage, componentImageSize, componentVersion, applyTime,
101 softwarePendingIn);
102
103 if (success)
104 {
105 if (applyTime == RequestedApplyTimes::Immediate)
106 {
107 softwareCurrent = std::move(softwarePendingIn);
108
109 // In case an immediate update is triggered after an update for
110 // onReset.
111 softwarePending = nullptr;
112
113 debug("Successfully updated to software version {SWID}", "SWID",
114 softwareCurrent->swid);
115 }
116 else if (applyTime == RequestedApplyTimes::OnReset)
117 {
118 softwarePending = std::move(softwarePendingIn);
119 }
120 }
121 else
122 {
123 softwarePendingIn->setActivation(ActivationFailed);
124 error("Failed to update the software for {SWID}", "SWID",
125 softwareCurrent->swid);
126 }
127
128 co_return success;
129}
130
131std::string Device::getEMConfigType() const
132{
133 return config.configType;
134}
135
136// NOLINTBEGIN(readability-static-accessed-through-instance)
137sdbusplus::async::task<bool> Device::resetDevice()
138// NOLINTEND(readability-static-accessed-through-instance)
139{
140 debug("Default implementation for device reset");
141
142 co_return true;
143}
144
145bool Device::setUpdateProgress(uint8_t progress) const
146{
147 if (!softwarePending || !softwarePending->softwareActivationProgress)
148 {
149 return false;
150 }
151
152 softwarePending->softwareActivationProgress->setProgress(progress);
153
154 return true;
155}
156
157// NOLINTBEGIN(readability-static-accessed-through-instance)
158sdbusplus::async::task<bool> Device::continueUpdateWithMappedPackage(
159 const uint8_t* matchingComponentImage, size_t componentImageSize,
160 const std::string& componentVersion, RequestedApplyTimes applyTime,
161 const std::unique_ptr<Software>& softwarePendingIn)
162// NOLINTEND(readability-static-accessed-through-instance)
163{
164 softwarePendingIn->setActivation(ActivationInterface::Activations::Ready);
165
166 softwarePendingIn->setVersion(componentVersion);
167
168 std::string objPath = softwarePendingIn->objectPath;
169
170 softwarePendingIn->softwareActivationProgress =
171 std::make_unique<SoftwareActivationProgress>(ctx, objPath.c_str());
172
173 softwarePendingIn->setActivationBlocksTransition(true);
174
175 softwarePendingIn->setActivation(
176 ActivationInterface::Activations::Activating);
177
178 bool success =
179 co_await updateDevice(matchingComponentImage, componentImageSize);
180
181 if (success)
182 {
183 softwarePendingIn->setActivation(
184 ActivationInterface::Activations::Active);
185 }
186
187 softwarePendingIn->setActivationBlocksTransition(false);
188
189 softwarePendingIn->softwareActivationProgress = nullptr;
190
191 if (!success)
192 {
193 // do not apply the update, it has failed.
194 // We can delete the new software version.
195
196 co_return false;
197 }
198
199 if (applyTime == applyTimeImmediate)
200 {
201 co_await resetDevice();
202
203 co_await softwarePendingIn->createInventoryAssociations(true);
204
205 softwarePendingIn->enableUpdate(allowedApplyTimes);
206 }
207 else
208 {
209 co_await softwarePendingIn->createInventoryAssociations(false);
210 }
211
212 co_return true;
213}