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