1 #pragma once
2 
3 #include <stdint.h>
4 #include <unistd.h>
5 
6 #include <filesystem>
7 #include <vector>
8 
9 #include "libpldm/base.h"
10 #include "oem/ibm/libpldm/file_io.h"
11 
12 namespace pldm
13 {
14 
15 namespace responder
16 {
17 
18 namespace oem_ibm
19 {
20 /** @brief Register handlers for command from the platform spec
21  */
22 void registerHandlers();
23 } // namespace oem_ibm
24 
25 using Response = std::vector<uint8_t>;
26 
27 namespace dma
28 {
29 
30 // The minimum data size of dma transfer in bytes
31 constexpr uint32_t minSize = 16;
32 
33 // 16MB - 4096B (16773120 bytes) is the maximum data size of DMA transfer
34 constexpr size_t maxSize = (16 * 1024 * 1024) - 4096;
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(const fs::path& path, uint32_t offset, uint32_t length,
62                          uint64_t address, bool upstream);
63 };
64 
65 /** @brief Transfer the data between BMC and host using DMA.
66  *
67  *  There is a max size for each DMA operation, transferAll API abstracts this
68  *  and the requested length is broken down into multiple DMA operations if the
69  *  length exceed max size.
70  *
71  * @tparam[in] T - DMA interface type
72  * @param[in] intf - interface passed to invoke DMA transfer
73  * @param[in] command  - PLDM command
74  * @param[in] path     - pathname of the file to transfer data from or to
75  * @param[in] offset   - offset in the file
76  * @param[in] length   - length of the data to transfer
77  * @param[in] address  - DMA address on the host
78  * @param[in] upstream - indicates direction of the transfer; true indicates
79  *                       transfer to the host
80  * @param[in] instanceId - Message's instance id
81  * @return PLDM response message
82  */
83 
84 template <class DMAInterface>
85 Response transferAll(DMAInterface* intf, uint8_t command, fs::path& path,
86                      uint32_t offset, uint32_t length, uint64_t address,
87                      bool upstream, uint8_t instanceId)
88 {
89     uint32_t origLength = length;
90     Response response(sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_RESP_BYTES, 0);
91     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
92 
93     while (length > dma::maxSize)
94     {
95         auto rc = intf->transferDataHost(path, offset, dma::maxSize, address,
96                                          upstream);
97         if (rc < 0)
98         {
99             encode_rw_file_memory_resp(instanceId, command, PLDM_ERROR, 0,
100                                        responsePtr);
101             return response;
102         }
103 
104         offset += dma::maxSize;
105         length -= dma::maxSize;
106         address += dma::maxSize;
107     }
108 
109     auto rc = intf->transferDataHost(path, offset, length, address, upstream);
110     if (rc < 0)
111     {
112         encode_rw_file_memory_resp(instanceId, command, PLDM_ERROR, 0,
113                                    responsePtr);
114         return response;
115     }
116 
117     encode_rw_file_memory_resp(instanceId, command, PLDM_SUCCESS, origLength,
118                                responsePtr);
119     return response;
120 }
121 
122 } // namespace dma
123 
124 /** @brief Handler for readFileIntoMemory command
125  *
126  *  @param[in] request - pointer to PLDM request payload
127  *  @param[in] payloadLength - length of the message
128  *
129  *  @return PLDM response message
130  */
131 Response readFileIntoMemory(const pldm_msg* request, size_t payloadLength);
132 
133 /** @brief Handler for writeFileIntoMemory command
134  *
135  *  @param[in] request - pointer to PLDM request payload
136  *  @param[in] payloadLength - length of the message
137  *
138  *  @return PLDM response message
139  */
140 Response writeFileFromMemory(const pldm_msg* request, size_t payloadLength);
141 
142 /** @brief Handler for GetFileTable command
143  *
144  *  @param[in] request - pointer to PLDM request payload
145  *  @param[in] payloadLength - length of the message payload
146  *
147  *  @return PLDM response message
148  */
149 Response getFileTable(const pldm_msg* request, size_t payloadLength);
150 } // namespace responder
151 } // namespace pldm
152