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 "pldmd/handler.hpp"
11 
12 #include <fcntl.h>
13 #include <stdint.h>
14 #include <sys/stat.h>
15 #include <sys/types.h>
16 #include <unistd.h>
17 
18 #include <filesystem>
19 #include <iostream>
20 #include <vector>
21 
22 namespace pldm
23 {
24 namespace responder
25 {
26 namespace dma
27 {
28 
29 // The minimum data size of dma transfer in bytes
30 constexpr uint32_t minSize = 16;
31 
32 constexpr size_t maxSize = DMA_MAXSIZE;
33 
34 namespace fs = std::filesystem;
35 
36 /**
37  * @class DMA
38  *
39  * Expose API to initiate transfer of data by DMA
40  *
41  * This class only exposes the public API transferDataHost to transfer data
42  * between BMC and host using DMA. This allows for mocking the transferDataHost
43  * for unit testing purposes.
44  */
45 class DMA
46 {
47   public:
48     /** @brief API to transfer data between BMC and host using DMA
49      *
50      * @param[in] path     - pathname of the file to transfer data from or to
51      * @param[in] offset   - offset in the file
52      * @param[in] length   - length of the data to transfer
53      * @param[in] address  - DMA address on the host
54      * @param[in] upstream - indicates direction of the transfer; true indicates
55      *                       transfer to the host
56      *
57      * @return returns 0 on success, negative errno on failure
58      */
59     int transferDataHost(int fd, uint32_t offset, uint32_t length,
60                          uint64_t address, bool upstream);
61 };
62 
63 /** @brief Transfer the data between BMC and host using DMA.
64  *
65  *  There is a max size for each DMA operation, transferAll API abstracts this
66  *  and the requested length is broken down into multiple DMA operations if the
67  *  length exceed max size.
68  *
69  * @tparam[in] T - DMA interface type
70  * @param[in] intf - interface passed to invoke DMA transfer
71  * @param[in] command  - PLDM command
72  * @param[in] path     - pathname of the file to transfer data from or to
73  * @param[in] offset   - offset in the file
74  * @param[in] length   - length of the data to transfer
75  * @param[in] address  - DMA address on the host
76  * @param[in] upstream - indicates direction of the transfer; true indicates
77  *                       transfer to the host
78  * @param[in] instanceId - Message's instance id
79  * @return PLDM response message
80  */
81 
82 template <class DMAInterface>
83 Response transferAll(DMAInterface* intf, uint8_t command, fs::path& path,
84                      uint32_t offset, uint32_t length, uint64_t address,
85                      bool upstream, uint8_t instanceId)
86 {
87     uint32_t origLength = length;
88     Response response(sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_RESP_BYTES, 0);
89     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
90 
91     int flags{};
92     if (upstream)
93     {
94         flags = O_RDONLY;
95     }
96     else if (fs::exists(path))
97     {
98         flags = O_RDWR;
99     }
100     else
101     {
102         flags = O_WRONLY;
103     }
104     int file = open(path.string().c_str(), flags);
105     if (file == -1)
106     {
107         std::cerr << "File does not exist, path = " << path.string() << "\n";
108         encode_rw_file_memory_resp(instanceId, command, PLDM_ERROR, 0,
109                                    responsePtr);
110         return response;
111     }
112     pldm::utils::CustomFD fd(file);
113 
114     while (length > dma::maxSize)
115     {
116         auto rc = intf->transferDataHost(fd(), offset, dma::maxSize, address,
117                                          upstream);
118         if (rc < 0)
119         {
120             encode_rw_file_memory_resp(instanceId, command, PLDM_ERROR, 0,
121                                        responsePtr);
122             return response;
123         }
124 
125         offset += dma::maxSize;
126         length -= dma::maxSize;
127         address += dma::maxSize;
128     }
129 
130     auto rc = intf->transferDataHost(fd(), offset, length, address, upstream);
131     if (rc < 0)
132     {
133         encode_rw_file_memory_resp(instanceId, command, PLDM_ERROR, 0,
134                                    responsePtr);
135         return response;
136     }
137 
138     encode_rw_file_memory_resp(instanceId, command, PLDM_SUCCESS, origLength,
139                                responsePtr);
140     return response;
141 }
142 
143 } // namespace dma
144 
145 namespace oem_ibm
146 {
147 class Handler : public CmdHandler
148 {
149   public:
150     Handler()
151     {
152         handlers.emplace(PLDM_READ_FILE_INTO_MEMORY,
153                          [this](const pldm_msg* request, size_t payloadLength) {
154                              return this->readFileIntoMemory(request,
155                                                              payloadLength);
156                          });
157         handlers.emplace(PLDM_WRITE_FILE_FROM_MEMORY,
158                          [this](const pldm_msg* request, size_t payloadLength) {
159                              return this->writeFileFromMemory(request,
160                                                               payloadLength);
161                          });
162         handlers.emplace(PLDM_WRITE_FILE_BY_TYPE_FROM_MEMORY,
163                          [this](const pldm_msg* request, size_t payloadLength) {
164                              return this->writeFileByTypeFromMemory(
165                                  request, payloadLength);
166                          });
167         handlers.emplace(PLDM_READ_FILE_BY_TYPE_INTO_MEMORY,
168                          [this](const pldm_msg* request, size_t payloadLength) {
169                              return this->readFileByTypeIntoMemory(
170                                  request, payloadLength);
171                          });
172         handlers.emplace(PLDM_READ_FILE_BY_TYPE, [this](const pldm_msg* request,
173                                                         size_t payloadLength) {
174             return this->readFileByType(request, payloadLength);
175         });
176         handlers.emplace(PLDM_WRITE_FILE_BY_TYPE,
177                          [this](const pldm_msg* request, size_t payloadLength) {
178                              return this->writeFileByType(request,
179                                                           payloadLength);
180                          });
181         handlers.emplace(PLDM_GET_FILE_TABLE,
182                          [this](const pldm_msg* request, size_t payloadLength) {
183                              return this->getFileTable(request, payloadLength);
184                          });
185         handlers.emplace(PLDM_READ_FILE,
186                          [this](const pldm_msg* request, size_t payloadLength) {
187                              return this->readFile(request, payloadLength);
188                          });
189         handlers.emplace(PLDM_WRITE_FILE,
190                          [this](const pldm_msg* request, size_t payloadLength) {
191                              return this->writeFile(request, payloadLength);
192                          });
193         handlers.emplace(PLDM_FILE_ACK,
194                          [this](const pldm_msg* request, size_t payloadLength) {
195                              return this->fileAck(request, payloadLength);
196                          });
197         handlers.emplace(PLDM_HOST_GET_ALERT_STATUS,
198                          [this](const pldm_msg* request, size_t payloadLength) {
199                              return this->getAlertStatus(request,
200                                                          payloadLength);
201                          });
202         handlers.emplace(PLDM_NEW_FILE_AVAILABLE,
203                          [this](const pldm_msg* request, size_t payloadLength) {
204                              return this->newFileAvailable(request,
205                                                            payloadLength);
206                          });
207     }
208 
209     /** @brief Handler for readFileIntoMemory command
210      *
211      *  @param[in] request - pointer to PLDM request payload
212      *  @param[in] payloadLength - length of the message
213      *
214      *  @return PLDM response message
215      */
216     Response readFileIntoMemory(const pldm_msg* request, size_t payloadLength);
217 
218     /** @brief Handler for writeFileIntoMemory command
219      *
220      *  @param[in] request - pointer to PLDM request payload
221      *  @param[in] payloadLength - length of the message
222      *
223      *  @return PLDM response message
224      */
225     Response writeFileFromMemory(const pldm_msg* request, size_t payloadLength);
226 
227     /** @brief Handler for writeFileByTypeFromMemory command
228      *
229      *  @param[in] request - pointer to PLDM request payload
230      *  @param[in] payloadLength - length of the message
231      *
232      *  @return PLDM response message
233      */
234 
235     Response writeFileByTypeFromMemory(const pldm_msg* request,
236                                        size_t payloadLength);
237 
238     /** @brief Handler for readFileByTypeIntoMemory command
239      *
240      *  @param[in] request - pointer to PLDM request payload
241      *  @param[in] payloadLength - length of the message
242      *
243      *  @return PLDM response message
244      */
245     Response readFileByTypeIntoMemory(const pldm_msg* request,
246                                       size_t payloadLength);
247 
248     /** @brief Handler for writeFileByType command
249      *
250      *  @param[in] request - pointer to PLDM request payload
251      *  @param[in] payloadLength - length of the message
252      *
253      *  @return PLDM response message
254      */
255     Response readFileByType(const pldm_msg* request, size_t payloadLength);
256 
257     Response writeFileByType(const pldm_msg* request, size_t payloadLength);
258 
259     /** @brief Handler for GetFileTable command
260      *
261      *  @param[in] request - pointer to PLDM request payload
262      *  @param[in] payloadLength - length of the message payload
263      *
264      *  @return PLDM response message
265      */
266     Response getFileTable(const pldm_msg* request, size_t payloadLength);
267 
268     /** @brief Handler for readFile command
269      *
270      *  @param[in] request - PLDM request msg
271      *  @param[in] payloadLength - length of the message payload
272      *
273      *  @return PLDM response message
274      */
275     Response readFile(const pldm_msg* request, size_t payloadLength);
276 
277     /** @brief Handler for writeFile command
278      *
279      *  @param[in] request - PLDM request msg
280      *  @param[in] payloadLength - length of the message payload
281      *
282      *  @return PLDM response message
283      */
284     Response writeFile(const pldm_msg* request, size_t payloadLength);
285 
286     Response fileAck(const pldm_msg* request, size_t payloadLength);
287 
288     /** @brief Handler for getAlertStatus command
289      *
290      *  @param[in] request - PLDM request msg
291      *  @param[in] payloadLength - length of the message payload
292      *
293      *  @return PLDM response message
294      */
295     Response getAlertStatus(const pldm_msg* request, size_t payloadLength);
296 
297     /** @brief Handler for newFileAvailable command
298      *
299      *  @param[in] request - PLDM request msg
300      *  @param[in] payloadLength - length of the message payload
301      *
302      *  @return PLDM response message
303      */
304     Response newFileAvailable(const pldm_msg* request, size_t payloadLength);
305 };
306 
307 } // namespace oem_ibm
308 } // namespace responder
309 } // namespace pldm
310