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/State/Host/client.hpp> 13 14 #include <utility> 15 16 PHOSPHOR_LOG2_USING; 17 18 using namespace phosphor::software::device; 19 20 const auto applyTimeImmediate = sdbusplus::common::xyz::openbmc_project:: 21 software::ApplyTime::RequestedApplyTimes::Immediate; 22 23 const auto ActivationInvalid = ActivationInterface::Activations::Invalid; 24 const auto ActivationFailed = ActivationInterface::Activations::Failed; 25 26 Device::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) 36 sdbusplus::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) 71 sdbusplus::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 std::unique_ptr<Software> softwarePendingOld = std::move(softwarePending); 100 101 softwarePending = std::move(softwarePendingIn); 102 softwarePendingIn = nullptr; 103 104 const bool success = co_await continueUpdateWithMappedPackage( 105 componentImage, componentImageSize, componentVersion, applyTime); 106 107 if (!success) 108 { 109 softwarePending->setActivation(ActivationFailed); 110 error("Failed to update the software for {SWID}", "SWID", 111 softwareCurrent->swid); 112 113 softwarePending = std::move(softwarePendingOld); 114 115 co_return false; 116 } 117 118 if (applyTime == RequestedApplyTimes::Immediate) 119 { 120 softwareCurrent = std::move(softwarePending); 121 122 // In case an immediate update is triggered after an update for 123 // onReset. 124 softwarePending = nullptr; 125 126 debug("Successfully updated to software version {SWID}", "SWID", 127 softwareCurrent->swid); 128 } 129 130 co_return true; 131 } 132 133 std::string Device::getEMConfigType() const 134 { 135 return config.configType; 136 } 137 138 // NOLINTBEGIN(readability-static-accessed-through-instance) 139 sdbusplus::async::task<bool> Device::resetDevice() 140 // NOLINTEND(readability-static-accessed-through-instance) 141 { 142 debug("Default implementation for device reset"); 143 144 co_return true; 145 } 146 147 bool Device::setUpdateProgress(uint8_t progress) const 148 { 149 if (!softwarePending || !softwarePending->softwareActivationProgress) 150 { 151 return false; 152 } 153 154 softwarePending->softwareActivationProgress->setProgress(progress); 155 156 return true; 157 } 158 159 // NOLINTBEGIN(readability-static-accessed-through-instance) 160 sdbusplus::async::task<bool> Device::continueUpdateWithMappedPackage( 161 const uint8_t* matchingComponentImage, size_t componentImageSize, 162 const std::string& componentVersion, RequestedApplyTimes applyTime) 163 // NOLINTEND(readability-static-accessed-through-instance) 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>(ctx, objPath.c_str()); 174 175 softwarePending->setActivationBlocksTransition(true); 176 177 softwarePending->setActivation( 178 ActivationInterface::Activations::Activating); 179 180 bool success = 181 co_await updateDevice(matchingComponentImage, componentImageSize); 182 183 if (success) 184 { 185 softwarePending->setActivation( 186 ActivationInterface::Activations::Active); 187 } 188 189 softwarePending->setActivationBlocksTransition(false); 190 191 softwarePending->softwareActivationProgress = nullptr; 192 193 if (!success) 194 { 195 // do not apply the update, it has failed. 196 // We can delete the new software version. 197 198 co_return false; 199 } 200 201 if (applyTime == applyTimeImmediate) 202 { 203 co_await resetDevice(); 204 205 co_await softwarePending->createInventoryAssociations(true); 206 207 softwarePending->enableUpdate(allowedApplyTimes); 208 } 209 else 210 { 211 co_await softwarePending->createInventoryAssociations(false); 212 } 213 214 co_return true; 215 } 216