1 #pragma once
2 
3 #include "config.h"
4 
5 #include "libpldm/base.h"
6 #include "oem/ibm/libpldm/file_io.h"
7 #include "oem/ibm/libpldm/host.h"
8 
9 #include "common/utils.hpp"
10 #include "oem/ibm/requester/dbus_to_file_handler.hpp"
11 #include "oem_ibm_handler.hpp"
12 #include "pldmd/handler.hpp"
13 
14 #include <fcntl.h>
15 #include <stdint.h>
16 #include <sys/stat.h>
17 #include <sys/types.h>
18 #include <unistd.h>
19 
20 #include <filesystem>
21 #include <iostream>
22 #include <vector>
23 
24 namespace pldm
25 {
26 namespace responder
27 {
28 namespace dma
29 {
30 
31 // The minimum data size of dma transfer in bytes
32 constexpr uint32_t minSize = 16;
33 
34 constexpr size_t maxSize = DMA_MAXSIZE;
35 
36 namespace fs = std::filesystem;
37 
38 /**
39  * @class DMA
40  *
41  * Expose API to initiate transfer of data by DMA
42  *
43  * This class only exposes the public API transferDataHost to transfer data
44  * between BMC and host using DMA. This allows for mocking the transferDataHost
45  * for unit testing purposes.
46  */
47 class DMA
48 {
49   public:
50     /** @brief API to transfer data between BMC and host using DMA
51      *
52      * @param[in] path     - pathname of the file to transfer data from or to
53      * @param[in] offset   - offset in the file
54      * @param[in] length   - length of the data to transfer
55      * @param[in] address  - DMA address on the host
56      * @param[in] upstream - indicates direction of the transfer; true indicates
57      *                       transfer to the host
58      *
59      * @return returns 0 on success, negative errno on failure
60      */
61     int transferDataHost(int fd, uint32_t offset, uint32_t length,
62                          uint64_t address, bool upstream);
63 
64     /** @brief API to transfer data on to unix socket from host using DMA
65      *
66      * @param[in] path     - pathname of the file to transfer data from or to
67      * @param[in] length   - length of the data to transfer
68      * @param[in] address  - DMA address on the host
69      *
70      * @return returns 0 on success, negative errno on failure
71      */
72     int transferHostDataToSocket(int fd, uint32_t length, uint64_t address);
73 };
74 
75 /** @brief Transfer the data between BMC and host using DMA.
76  *
77  *  There is a max size for each DMA operation, transferAll API abstracts this
78  *  and the requested length is broken down into multiple DMA operations if the
79  *  length exceed max size.
80  *
81  * @tparam[in] T - DMA interface type
82  * @param[in] intf - interface passed to invoke DMA transfer
83  * @param[in] command  - PLDM command
84  * @param[in] path     - pathname of the file to transfer data from or to
85  * @param[in] offset   - offset in the file
86  * @param[in] length   - length of the data to transfer
87  * @param[in] address  - DMA address on the host
88  * @param[in] upstream - indicates direction of the transfer; true indicates
89  *                       transfer to the host
90  * @param[in] instanceId - Message's instance id
91  * @return PLDM response message
92  */
93 
94 template <class DMAInterface>
95 Response transferAll(DMAInterface* intf, uint8_t command, fs::path& path,
96                      uint32_t offset, uint32_t length, uint64_t address,
97                      bool upstream, uint8_t instanceId)
98 {
99     uint32_t origLength = length;
100     Response response(sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_RESP_BYTES, 0);
101     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
102 
103     int flags{};
104     if (upstream)
105     {
106         flags = O_RDONLY;
107     }
108     else if (fs::exists(path))
109     {
110         flags = O_RDWR;
111     }
112     else
113     {
114         flags = O_WRONLY;
115     }
116     int file = open(path.string().c_str(), flags);
117     if (file == -1)
118     {
119         std::cerr << "File does not exist, path = " << path.string() << "\n";
120         encode_rw_file_memory_resp(instanceId, command, PLDM_ERROR, 0,
121                                    responsePtr);
122         return response;
123     }
124     pldm::utils::CustomFD fd(file);
125 
126     while (length > dma::maxSize)
127     {
128         auto rc = intf->transferDataHost(fd(), offset, dma::maxSize, address,
129                                          upstream);
130         if (rc < 0)
131         {
132             encode_rw_file_memory_resp(instanceId, command, PLDM_ERROR, 0,
133                                        responsePtr);
134             return response;
135         }
136 
137         offset += dma::maxSize;
138         length -= dma::maxSize;
139         address += dma::maxSize;
140     }
141 
142     auto rc = intf->transferDataHost(fd(), offset, length, address, upstream);
143     if (rc < 0)
144     {
145         encode_rw_file_memory_resp(instanceId, command, PLDM_ERROR, 0,
146                                    responsePtr);
147         return response;
148     }
149 
150     encode_rw_file_memory_resp(instanceId, command, PLDM_SUCCESS, origLength,
151                                responsePtr);
152     return response;
153 }
154 
155 } // namespace dma
156 
157 namespace oem_ibm
158 {
159 static constexpr auto dumpObjPath = "/xyz/openbmc_project/dump/resource/entry/";
160 static constexpr auto resDumpEntry = "com.ibm.Dump.Entry.Resource";
161 class Handler : public CmdHandler
162 {
163   public:
164     Handler(oem_platform::Handler* oemPlatformHandler, int hostSockFd,
165             uint8_t hostEid, dbus_api::Requester* dbusImplReqester) :
166         oemPlatformHandler(oemPlatformHandler),
167         hostSockFd(hostSockFd), hostEid(hostEid),
168         dbusImplReqester(dbusImplReqester)
169     {
170         handlers.emplace(PLDM_READ_FILE_INTO_MEMORY,
171                          [this](const pldm_msg* request, size_t payloadLength) {
172                              return this->readFileIntoMemory(request,
173                                                              payloadLength);
174                          });
175         handlers.emplace(PLDM_WRITE_FILE_FROM_MEMORY,
176                          [this](const pldm_msg* request, size_t payloadLength) {
177                              return this->writeFileFromMemory(request,
178                                                               payloadLength);
179                          });
180         handlers.emplace(PLDM_WRITE_FILE_BY_TYPE_FROM_MEMORY,
181                          [this](const pldm_msg* request, size_t payloadLength) {
182                              return this->writeFileByTypeFromMemory(
183                                  request, payloadLength);
184                          });
185         handlers.emplace(PLDM_READ_FILE_BY_TYPE_INTO_MEMORY,
186                          [this](const pldm_msg* request, size_t payloadLength) {
187                              return this->readFileByTypeIntoMemory(
188                                  request, payloadLength);
189                          });
190         handlers.emplace(PLDM_READ_FILE_BY_TYPE, [this](const pldm_msg* request,
191                                                         size_t payloadLength) {
192             return this->readFileByType(request, payloadLength);
193         });
194         handlers.emplace(PLDM_WRITE_FILE_BY_TYPE,
195                          [this](const pldm_msg* request, size_t payloadLength) {
196                              return this->writeFileByType(request,
197                                                           payloadLength);
198                          });
199         handlers.emplace(PLDM_GET_FILE_TABLE,
200                          [this](const pldm_msg* request, size_t payloadLength) {
201                              return this->getFileTable(request, payloadLength);
202                          });
203         handlers.emplace(PLDM_READ_FILE,
204                          [this](const pldm_msg* request, size_t payloadLength) {
205                              return this->readFile(request, payloadLength);
206                          });
207         handlers.emplace(PLDM_WRITE_FILE,
208                          [this](const pldm_msg* request, size_t payloadLength) {
209                              return this->writeFile(request, payloadLength);
210                          });
211         handlers.emplace(PLDM_FILE_ACK,
212                          [this](const pldm_msg* request, size_t payloadLength) {
213                              return this->fileAck(request, payloadLength);
214                          });
215         handlers.emplace(PLDM_HOST_GET_ALERT_STATUS,
216                          [this](const pldm_msg* request, size_t payloadLength) {
217                              return this->getAlertStatus(request,
218                                                          payloadLength);
219                          });
220         handlers.emplace(PLDM_NEW_FILE_AVAILABLE,
221                          [this](const pldm_msg* request, size_t payloadLength) {
222                              return this->newFileAvailable(request,
223                                                            payloadLength);
224                          });
225 
226         resDumpMatcher = std::make_unique<sdbusplus::bus::match::match>(
227             pldm::utils::DBusHandler::getBus(),
228             sdbusplus::bus::match::rules::interfacesAdded() +
229                 sdbusplus::bus::match::rules::argNpath(0, dumpObjPath),
230             [hostSockFd, hostEid,
231              dbusImplReqester](sdbusplus::message::message& msg) {
232                 std::map<
233                     std::string,
234                     std::map<std::string, std::variant<std::string, uint32_t>>>
235                     interfaces;
236                 sdbusplus::message::object_path path;
237                 msg.read(path, interfaces);
238                 std::string vspstring;
239                 std::string password;
240 
241                 for (auto& interface : interfaces)
242                 {
243                     if (interface.first == resDumpEntry)
244                     {
245                         for (const auto& property : interface.second)
246                         {
247                             if (property.first == "VSPString")
248                             {
249                                 vspstring =
250                                     std::get<std::string>(property.second);
251                             }
252                             else if (property.first == "Password")
253                             {
254                                 password =
255                                     std::get<std::string>(property.second);
256                             }
257                         }
258                         auto dbusToFileHandler = std::make_unique<
259                             pldm::requester::oem_ibm::DbusToFileHandler>(
260                             hostSockFd, hostEid, dbusImplReqester, path);
261                         dbusToFileHandler->processNewResourceDump(vspstring,
262                                                                   password);
263                         break;
264                     }
265                 }
266             });
267     }
268 
269     /** @brief Handler for readFileIntoMemory command
270      *
271      *  @param[in] request - pointer to PLDM request payload
272      *  @param[in] payloadLength - length of the message
273      *
274      *  @return PLDM response message
275      */
276     Response readFileIntoMemory(const pldm_msg* request, size_t payloadLength);
277 
278     /** @brief Handler for writeFileIntoMemory command
279      *
280      *  @param[in] request - pointer to PLDM request payload
281      *  @param[in] payloadLength - length of the message
282      *
283      *  @return PLDM response message
284      */
285     Response writeFileFromMemory(const pldm_msg* request, size_t payloadLength);
286 
287     /** @brief Handler for writeFileByTypeFromMemory command
288      *
289      *  @param[in] request - pointer to PLDM request payload
290      *  @param[in] payloadLength - length of the message
291      *
292      *  @return PLDM response message
293      */
294 
295     Response writeFileByTypeFromMemory(const pldm_msg* request,
296                                        size_t payloadLength);
297 
298     /** @brief Handler for readFileByTypeIntoMemory command
299      *
300      *  @param[in] request - pointer to PLDM request payload
301      *  @param[in] payloadLength - length of the message
302      *
303      *  @return PLDM response message
304      */
305     Response readFileByTypeIntoMemory(const pldm_msg* request,
306                                       size_t payloadLength);
307 
308     /** @brief Handler for writeFileByType command
309      *
310      *  @param[in] request - pointer to PLDM request payload
311      *  @param[in] payloadLength - length of the message
312      *
313      *  @return PLDM response message
314      */
315     Response readFileByType(const pldm_msg* request, size_t payloadLength);
316 
317     Response writeFileByType(const pldm_msg* request, size_t payloadLength);
318 
319     /** @brief Handler for GetFileTable command
320      *
321      *  @param[in] request - pointer to PLDM request payload
322      *  @param[in] payloadLength - length of the message payload
323      *
324      *  @return PLDM response message
325      */
326     Response getFileTable(const pldm_msg* request, size_t payloadLength);
327 
328     /** @brief Handler for readFile command
329      *
330      *  @param[in] request - PLDM request msg
331      *  @param[in] payloadLength - length of the message payload
332      *
333      *  @return PLDM response message
334      */
335     Response readFile(const pldm_msg* request, size_t payloadLength);
336 
337     /** @brief Handler for writeFile command
338      *
339      *  @param[in] request - PLDM request msg
340      *  @param[in] payloadLength - length of the message payload
341      *
342      *  @return PLDM response message
343      */
344     Response writeFile(const pldm_msg* request, size_t payloadLength);
345 
346     Response fileAck(const pldm_msg* request, size_t payloadLength);
347 
348     /** @brief Handler for getAlertStatus command
349      *
350      *  @param[in] request - PLDM request msg
351      *  @param[in] payloadLength - length of the message payload
352      *
353      *  @return PLDM response message
354      */
355     Response getAlertStatus(const pldm_msg* request, size_t payloadLength);
356 
357     /** @brief Handler for newFileAvailable command
358      *
359      *  @param[in] request - PLDM request msg
360      *  @param[in] payloadLength - length of the message payload
361      *
362      *  @return PLDM response message
363      */
364     Response newFileAvailable(const pldm_msg* request, size_t payloadLength);
365 
366   private:
367     oem_platform::Handler* oemPlatformHandler;
368     int hostSockFd;
369     uint8_t hostEid;
370     dbus_api::Requester* dbusImplReqester;
371     using DBusInterfaceAdded = std::vector<std::pair<
372         std::string,
373         std::vector<std::pair<std::string, std::variant<std::string>>>>>;
374     std::unique_ptr<sdbusplus::bus::match::match>
375         resDumpMatcher; //!< Pointer to capture the interface added signal
376                         //!< for new resource dump
377 };
378 
379 } // namespace oem_ibm
380 } // namespace responder
381 } // namespace pldm
382