blob: 17a6fe24afc91d313d603e5387fc71fb72fe58e9 [file] [log] [blame]
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +05301#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
11namespace pldm
12{
13
14namespace responder
15{
16
17using Response = std::vector<uint8_t>;
18
19namespace utils
20{
21
22/** @struct CustomFD
23 *
24 * RAII wrapper for file descriptor.
25 */
26struct CustomFD
27{
28 CustomFD(const CustomFD&) = delete;
29 CustomFD& operator=(const CustomFD&) = delete;
30 CustomFD(CustomFD&&) = delete;
31 CustomFD& operator=(CustomFD&&) = delete;
32
33 CustomFD(int fd) : fd(fd)
34 {
35 }
36
37 ~CustomFD()
38 {
39 if (fd >= 0)
40 {
41 close(fd);
42 }
43 }
44
45 int operator()() const
46 {
47 return fd;
48 }
49
50 private:
51 int fd = -1;
52};
53
54} // namespace utils
55
56namespace dma
57{
58
59// The minimum data size of dma transfer in bytes
60constexpr uint32_t minSize = 16;
61
62// 16MB - 4096B (16773120 bytes) is the maximum data size of DMA transfer
63constexpr size_t maxSize = (16 * 1024 * 1024) - 4096;
64
65namespace fs = std::filesystem;
66
67/**
68 * @class DMA
69 *
70 * Expose API to initiate transfer of data by DMA
71 *
72 * This class only exposes the public API transferDataHost to transfer data
73 * between BMC and host using DMA. This allows for mocking the transferDataHost
74 * for unit testing purposes.
75 */
76class DMA
77{
78 public:
79 /** @brief API to transfer data between BMC and host using DMA
80 *
81 * @param[in] path - pathname of the file to transfer data from or to
82 * @param[in] offset - offset in the file
83 * @param[in] length - length of the data to transfer
84 * @param[in] address - DMA address on the host
85 * @param[in] upstream - indicates direction of the transfer; true indicates
86 * transfer to the host
87 *
88 * @return returns 0 on success, negative errno on failure
89 */
90 int transferDataHost(const fs::path& path, uint32_t offset, uint32_t length,
91 uint64_t address, bool upstream);
92};
93
94/** @brief Transfer the data between BMC and host using DMA.
95 *
96 * There is a max size for each DMA operation, transferAll API abstracts this
97 * and the requested length is broken down into multiple DMA operations if the
98 * length exceed max size.
99 *
100 * @tparam[in] T - DMA interface type
101 * @param[in] intf - interface passed to invoke DMA transfer
102 * @param[in] command - PLDM command
103 * @param[in] path - pathname of the file to transfer data from or to
104 * @param[in] offset - offset in the file
105 * @param[in] length - length of the data to transfer
106 * @param[in] address - DMA address on the host
107 * @param[in] upstream - indicates direction of the transfer; true indicates
108 * transfer to the host
109 * @return PLDM response message
110 */
111
112template <class DMAInterface>
113Response transferAll(DMAInterface* intf, uint8_t command, fs::path& path,
114 uint32_t offset, uint32_t length, uint64_t address,
115 bool upstream)
116{
117 uint32_t origLength = length;
118 Response response(sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_RESP_BYTES, 0);
119 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
120
121 while (length > dma::maxSize)
122 {
123 auto rc = intf->transferDataHost(path, offset, dma::maxSize, address,
124 upstream);
125 if (rc < 0)
126 {
127 encode_rw_file_memory_resp(0, command, PLDM_ERROR, 0, responsePtr);
128 return response;
129 }
130
131 offset += dma::maxSize;
132 length -= dma::maxSize;
133 address += dma::maxSize;
134 }
135
136 auto rc = intf->transferDataHost(path, offset, length, address, upstream);
137 if (rc < 0)
138 {
139 encode_rw_file_memory_resp(0, command, PLDM_ERROR, 0, responsePtr);
140 return response;
141 }
142
143 encode_rw_file_memory_resp(0, command, PLDM_SUCCESS, origLength,
144 responsePtr);
145 return response;
146}
147
148} // namespace dma
149
150/** @brief Handler for readFileIntoMemory command
151 *
152 * @param[in] request - pointer to PLDM request payload
153 * @param[in] payloadLength - length of the message payload
154 *
155 * @return PLDM response message
156 */
157Response readFileIntoMemory(const uint8_t* request, size_t payloadLength);
158
159/** @brief Handler for writeFileIntoMemory command
160 *
161 * @param[in] request - pointer to PLDM request payload
162 * @param[in] payloadLength - length of the message payload
163 *
164 * @return PLDM response message
165 */
166Response writeFileFromMemory(const uint8_t* request, size_t payloadLength);
167} // namespace responder
168} // namespace pldm