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