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