xref: /openbmc/pldm/fw-update/update_manager.hpp (revision 6a3f9906a774644a8f0ca2978a81b769e948206f)
1 #pragma once
2 
3 #include "common/instance_id.hpp"
4 #include "common/types.hpp"
5 #include "device_updater.hpp"
6 #include "fw-update/activation.hpp"
7 #include "fw-update/update.hpp"
8 #ifdef FW_UPDATE_INOTIFY_ENABLED
9 #include "fw-update/watch.hpp"
10 #endif
11 #include "package_parser.hpp"
12 #include "requester/handler.hpp"
13 
14 #include <libpldm/base.h>
15 
16 #include <sdbusplus/async.hpp>
17 #include <sdbusplus/server/object.hpp>
18 #include <xyz/openbmc_project/Software/Activation/server.hpp>
19 
20 #include <chrono>
21 #include <filesystem>
22 #include <fstream>
23 #include <sstream>
24 #include <tuple>
25 #include <unordered_map>
26 
27 namespace pldm
28 {
29 
30 namespace fw_update
31 {
32 
33 using namespace sdeventplus;
34 using namespace sdeventplus::source;
35 using namespace pldm;
36 
37 using DeviceIDRecordOffset = size_t;
38 using DeviceUpdaterInfo = std::pair<mctp_eid_t, DeviceIDRecordOffset>;
39 using DeviceUpdaterInfos = std::vector<DeviceUpdaterInfo>;
40 using TotalComponentUpdates = size_t;
41 
42 class UpdateManager
43 {
44   public:
45     UpdateManager() = delete;
46     UpdateManager(const UpdateManager&) = delete;
47     UpdateManager(UpdateManager&&) = delete;
48     UpdateManager& operator=(const UpdateManager&) = delete;
49     UpdateManager& operator=(UpdateManager&&) = delete;
50     ~UpdateManager() = default;
51 
UpdateManager(Event & event,pldm::requester::Handler<pldm::requester::Request> & handler,InstanceIdDb & instanceIdDb,const DescriptorMap & descriptorMap,const ComponentInfoMap & componentInfoMap)52     explicit UpdateManager(
53         Event& event,
54         pldm::requester::Handler<pldm::requester::Request>& handler,
55         InstanceIdDb& instanceIdDb, const DescriptorMap& descriptorMap,
56         const ComponentInfoMap& componentInfoMap) :
57         event(event), handler(handler), instanceIdDb(instanceIdDb),
58         descriptorMap(descriptorMap), componentInfoMap(componentInfoMap),
59 #ifdef FW_UPDATE_INOTIFY_ENABLED
60         watch(event.get(),
61               [this](std::string& packageFilePath) {
62                   return this->processPackage(
63                       std::filesystem::path(packageFilePath));
64               }),
65 #else
66         updater(std::make_unique<Update>(pldm::utils::DBusHandler::getBus(),
67                                          "/xyz/openbmc_project/software/pldm",
68                                          this)),
69 #endif
70         totalNumComponentUpdates(0), compUpdateCompletedCount(0)
71     {}
72 
73     /** @brief Handle PLDM request for the commands in the FW update
74      *         specification
75      *
76      *  @param[in] eid - Remote MCTP Endpoint ID
77      *  @param[in] command - PLDM command code
78      *  @param[in] request - PLDM request message
79      *  @param[in] requestLen - PLDM request message length
80      *
81      *  @return PLDM response message
82      */
83     Response handleRequest(mctp_eid_t eid, uint8_t command,
84                            const pldm_msg* request, size_t reqMsgLen);
85 
86     int processPackage(const std::filesystem::path& packageFilePath);
87 
88     /** @brief Process the firmware update package
89      *
90      *  @param[in] packageStream - Stream of the firmware update package
91      *  @param[in] packageSize - Size of the firmware update package
92      *
93      *  @return Object path of the created Software object
94      */
95     void processStream(std::istream& packageStream, uintmax_t packageSize);
96 
97     /** @brief Defers processing the package stream
98      *
99      *  @param[in] packageStream - Stream of the firmware update package
100      *  @param[in] packageSize - Size of the firmware update package
101      *
102      *  @return Object path of the created Software object as a string
103      */
104     std::string processStreamDefer(std::istream& packageStream,
105                                    uintmax_t packageSize);
106 
107     void updateDeviceCompletion(mctp_eid_t eid, bool status);
108 
109     void updateActivationProgress();
110 
111     /** @brief Callback function that will be invoked when the
112      *         RequestedActivation will be set to active in the Activation
113      *         interface
114      */
115     void activatePackage();
116 
117     void clearActivationInfo();
118 
119     /** @brief
120      *
121      */
122     DeviceUpdaterInfos associatePkgToDevices(
123         const FirmwareDeviceIDRecords& fwDeviceIDRecords,
124         const DescriptorMap& descriptorMap,
125         TotalComponentUpdates& totalNumComponentUpdates);
126 
127     /** @brief Generate a unique software ID based on current timestamp
128      *
129      *  @return String representation of the current timestamp in seconds
130      */
131     static std::string getSwId();
132 
133     const std::string swRootPath{"/xyz/openbmc_project/software/"};
134     Event& event; //!< reference to PLDM daemon's main event loop
135     /** @brief PLDM request handler */
136     pldm::requester::Handler<pldm::requester::Request>& handler;
137     InstanceIdDb& instanceIdDb; //!< reference to an InstanceIdDb
138 
139     std::unique_ptr<Activation> activation;
140 
141   private:
142     /** @brief Device identifiers of the managed FDs */
143     const DescriptorMap& descriptorMap;
144     /** @brief Component information needed for the update of the managed FDs */
145     const ComponentInfoMap& componentInfoMap;
146 #ifdef FW_UPDATE_INOTIFY_ENABLED
147     Watch watch;
148 #else
149     std::unique_ptr<Update> updater;
150 #endif
151 
152     std::unique_ptr<ActivationProgress> activationProgress;
153     std::string objPath;
154 
155     std::filesystem::path fwPackageFilePath;
156     std::unique_ptr<PackageParser> parser;
157     std::ifstream package;
158 
159     std::unordered_map<mctp_eid_t, std::unique_ptr<DeviceUpdater>>
160         deviceUpdaterMap;
161     std::unordered_map<mctp_eid_t, bool> deviceUpdateCompletionMap;
162 
163     /** @brief Total number of component updates to calculate the progress of
164      *         the Firmware activation
165      */
166     size_t totalNumComponentUpdates;
167 
168     /** @brief FW update package can contain updates for multiple firmware
169      *         devices and each device can have multiple components. Once
170      *         each component is updated (Transfer completed, Verified and
171      *         Applied) ActivationProgress is updated.
172      */
173     size_t compUpdateCompletedCount;
174     decltype(std::chrono::steady_clock::now()) startTime;
175     std::unique_ptr<sdeventplus::source::Defer> updateDeferHandler;
176 };
177 
178 } // namespace fw_update
179 
180 } // namespace pldm
181