1 #pragma once
2 
3 #include "handler.hpp"
4 
5 #include <stdint.h>
6 #include <unistd.h>
7 
8 #include <filesystem>
9 #include <vector>
10 
11 #include "libpldm/base.h"
12 #include "oem/ibm/libpldm/file_io.h"
13 
14 namespace pldm
15 {
16 namespace responder
17 {
18 namespace dma
19 {
20 
21 // The minimum data size of dma transfer in bytes
22 constexpr uint32_t minSize = 16;
23 
24 // 16MB - 4096B (16773120 bytes) is the maximum data size of DMA transfer
25 constexpr size_t maxSize = (16 * 1024 * 1024) - 4096;
26 
27 namespace fs = std::filesystem;
28 
29 /**
30  * @class DMA
31  *
32  * Expose API to initiate transfer of data by DMA
33  *
34  * This class only exposes the public API transferDataHost to transfer data
35  * between BMC and host using DMA. This allows for mocking the transferDataHost
36  * for unit testing purposes.
37  */
38 class DMA
39 {
40   public:
41     /** @brief API to transfer data between BMC and host using DMA
42      *
43      * @param[in] path     - pathname of the file to transfer data from or to
44      * @param[in] offset   - offset in the file
45      * @param[in] length   - length of the data to transfer
46      * @param[in] address  - DMA address on the host
47      * @param[in] upstream - indicates direction of the transfer; true indicates
48      *                       transfer to the host
49      *
50      * @return returns 0 on success, negative errno on failure
51      */
52     int transferDataHost(const fs::path& path, uint32_t offset, uint32_t length,
53                          uint64_t address, bool upstream);
54 };
55 
56 /** @brief Transfer the data between BMC and host using DMA.
57  *
58  *  There is a max size for each DMA operation, transferAll API abstracts this
59  *  and the requested length is broken down into multiple DMA operations if the
60  *  length exceed max size.
61  *
62  * @tparam[in] T - DMA interface type
63  * @param[in] intf - interface passed to invoke DMA transfer
64  * @param[in] command  - PLDM command
65  * @param[in] path     - pathname of the file to transfer data from or to
66  * @param[in] offset   - offset in the file
67  * @param[in] length   - length of the data to transfer
68  * @param[in] address  - DMA address on the host
69  * @param[in] upstream - indicates direction of the transfer; true indicates
70  *                       transfer to the host
71  * @param[in] instanceId - Message's instance id
72  * @return PLDM response message
73  */
74 
75 template <class DMAInterface>
76 Response transferAll(DMAInterface* intf, uint8_t command, fs::path& path,
77                      uint32_t offset, uint32_t length, uint64_t address,
78                      bool upstream, uint8_t instanceId)
79 {
80     uint32_t origLength = length;
81     Response response(sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_RESP_BYTES, 0);
82     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
83 
84     while (length > dma::maxSize)
85     {
86         auto rc = intf->transferDataHost(path, offset, dma::maxSize, address,
87                                          upstream);
88         if (rc < 0)
89         {
90             encode_rw_file_memory_resp(instanceId, command, PLDM_ERROR, 0,
91                                        responsePtr);
92             return response;
93         }
94 
95         offset += dma::maxSize;
96         length -= dma::maxSize;
97         address += dma::maxSize;
98     }
99 
100     auto rc = intf->transferDataHost(path, offset, length, address, upstream);
101     if (rc < 0)
102     {
103         encode_rw_file_memory_resp(instanceId, command, PLDM_ERROR, 0,
104                                    responsePtr);
105         return response;
106     }
107 
108     encode_rw_file_memory_resp(instanceId, command, PLDM_SUCCESS, origLength,
109                                responsePtr);
110     return response;
111 }
112 
113 } // namespace dma
114 
115 namespace oem_ibm
116 {
117 
118 class Handler : public CmdHandler
119 {
120   public:
121     Handler()
122     {
123         handlers.emplace(PLDM_READ_FILE_INTO_MEMORY,
124                          [this](const pldm_msg* request, size_t payloadLength) {
125                              return this->readFileIntoMemory(request,
126                                                              payloadLength);
127                          });
128         handlers.emplace(PLDM_WRITE_FILE_FROM_MEMORY,
129                          [this](const pldm_msg* request, size_t payloadLength) {
130                              return this->writeFileFromMemory(request,
131                                                               payloadLength);
132                          });
133         handlers.emplace(PLDM_WRITE_FILE_BY_TYPE_FROM_MEMORY,
134                          [this](const pldm_msg* request, size_t payloadLength) {
135                              return this->writeFileByTypeFromMemory(
136                                  request, payloadLength);
137                          });
138         handlers.emplace(PLDM_READ_FILE_BY_TYPE_INTO_MEMORY,
139                          [this](const pldm_msg* request, size_t payloadLength) {
140                              return this->readFileByTypeIntoMemory(
141                                  request, payloadLength);
142                          });
143         handlers.emplace(PLDM_READ_FILE_BY_TYPE, [this](const pldm_msg* request,
144                                                         size_t payloadLength) {
145             return this->readFileByType(request, payloadLength);
146         });
147         handlers.emplace(PLDM_GET_FILE_TABLE,
148                          [this](const pldm_msg* request, size_t payloadLength) {
149                              return this->getFileTable(request, payloadLength);
150                          });
151         handlers.emplace(PLDM_READ_FILE,
152                          [this](const pldm_msg* request, size_t payloadLength) {
153                              return this->readFile(request, payloadLength);
154                          });
155         handlers.emplace(PLDM_WRITE_FILE,
156                          [this](const pldm_msg* request, size_t payloadLength) {
157                              return this->writeFile(request, payloadLength);
158                          });
159     }
160 
161     /** @brief Handler for readFileIntoMemory command
162      *
163      *  @param[in] request - pointer to PLDM request payload
164      *  @param[in] payloadLength - length of the message
165      *
166      *  @return PLDM response message
167      */
168     Response readFileIntoMemory(const pldm_msg* request, size_t payloadLength);
169 
170     /** @brief Handler for writeFileIntoMemory command
171      *
172      *  @param[in] request - pointer to PLDM request payload
173      *  @param[in] payloadLength - length of the message
174      *
175      *  @return PLDM response message
176      */
177     Response writeFileFromMemory(const pldm_msg* request, size_t payloadLength);
178 
179     /** @brief Handler for writeFileByTypeFromMemory command
180      *
181      *  @param[in] request - pointer to PLDM request payload
182      *  @param[in] payloadLength - length of the message
183      *
184      *  @return PLDM response message
185      */
186 
187     Response writeFileByTypeFromMemory(const pldm_msg* request,
188                                        size_t payloadLength);
189 
190     /** @brief Handler for readFileByTypeIntoMemory command
191      *
192      *  @param[in] request - pointer to PLDM request payload
193      *  @param[in] payloadLength - length of the message
194      *
195      *  @return PLDM response message
196      */
197     Response readFileByTypeIntoMemory(const pldm_msg* request,
198                                       size_t payloadLength);
199 
200     /** @brief Handler for readFileByType command
201      *
202      *  @param[in] request - pointer to PLDM request payload
203      *  @param[in] payloadLength - length of the message
204      *
205      *  @return PLDM response message
206      */
207     Response readFileByType(const pldm_msg* request, size_t payloadLength);
208 
209     /** @brief Handler for GetFileTable command
210      *
211      *  @param[in] request - pointer to PLDM request payload
212      *  @param[in] payloadLength - length of the message payload
213      *
214      *  @return PLDM response message
215      */
216     Response getFileTable(const pldm_msg* request, size_t payloadLength);
217 
218     /** @brief Handler for readFile command
219      *
220      *  @param[in] request - PLDM request msg
221      *  @param[in] payloadLength - length of the message payload
222      *
223      *  @return PLDM response message
224      */
225     Response readFile(const pldm_msg* request, size_t payloadLength);
226 
227     /** @brief Handler for writeFile command
228      *
229      *  @param[in] request - PLDM request msg
230      *  @param[in] payloadLength - length of the message payload
231      *
232      *  @return PLDM response message
233      */
234     Response writeFile(const pldm_msg* request, size_t payloadLength);
235 };
236 
237 } // namespace oem_ibm
238 } // namespace responder
239 } // namespace pldm
240