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