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