blob: 9cf093caa95cd5021c6a9de3244a43b426519942 [file] [log] [blame]
Tom Josephf8329ac2019-04-11 22:13:22 +05301#include "file_io.hpp"
2
3#include <fcntl.h>
4#include <sys/mman.h>
5#include <sys/stat.h>
6#include <sys/types.h>
7#include <unistd.h>
8
9#include <cstring>
10#include <fstream>
11#include <phosphor-logging/log.hpp>
12
13#include "libpldm/base.h"
14
15namespace pldm
16{
17
18namespace responder
19{
20
21namespace fs = std::filesystem;
22using namespace phosphor::logging;
23
Eddie James3b02e272019-04-22 20:13:55 +000024namespace dma
Tom Josephf8329ac2019-04-11 22:13:22 +053025{
Eddie James3b02e272019-04-22 20:13:55 +000026
27/** @struct AspeedXdmaOp
28 *
29 * Structure representing XDMA operation
30 */
31struct AspeedXdmaOp
32{
Eddie James3b02e272019-04-22 20:13:55 +000033 uint64_t hostAddr; //!< the DMA address on the host side, configured by
34 //!< PCI subsystem.
35 uint32_t len; //!< the size of the transfer in bytes, it should be a
36 //!< multiple of 16 bytes
Eddie Jamesc6da21e2019-05-29 18:29:58 +000037 uint32_t upstream; //!< boolean indicating the direction of the DMA
38 //!< operation, true means a transfer from BMC to host.
39};
Eddie James3b02e272019-04-22 20:13:55 +000040
41constexpr auto xdmaDev = "/dev/xdma";
42
Tom Joseph55306762019-05-02 09:11:26 +053043int DMA::transferDataHost(const fs::path& path, uint32_t offset,
44 uint32_t length, uint64_t address, bool upstream)
Eddie James3b02e272019-04-22 20:13:55 +000045{
Tom Josephf8329ac2019-04-11 22:13:22 +053046 static const size_t pageSize = getpagesize();
47 uint32_t numPages = length / pageSize;
Eddie James3b02e272019-04-22 20:13:55 +000048 uint32_t pageAlignedLength = numPages * pageSize;
49
50 if (length > pageAlignedLength)
Tom Josephf8329ac2019-04-11 22:13:22 +053051 {
Eddie James3b02e272019-04-22 20:13:55 +000052 pageAlignedLength += pageSize;
Tom Josephf8329ac2019-04-11 22:13:22 +053053 }
54
Eddie James3b02e272019-04-22 20:13:55 +000055 auto mmapCleanup = [pageAlignedLength](void* vgaMem) {
56 munmap(vgaMem, pageAlignedLength);
Tom Josephf8329ac2019-04-11 22:13:22 +053057 };
58
59 int fd = -1;
60 int rc = 0;
Eddie James3b02e272019-04-22 20:13:55 +000061 fd = open(xdmaDev, O_RDWR);
Tom Josephf8329ac2019-04-11 22:13:22 +053062 if (fd < 0)
63 {
Eddie James3b02e272019-04-22 20:13:55 +000064 rc = -errno;
65 log<level::ERR>("Failed to open the XDMA device", entry("RC=%d", rc));
Tom Josephf8329ac2019-04-11 22:13:22 +053066 return rc;
67 }
Tom Josephf8329ac2019-04-11 22:13:22 +053068
Eddie James3b02e272019-04-22 20:13:55 +000069 utils::CustomFD xdmaFd(fd);
Tom Josephf8329ac2019-04-11 22:13:22 +053070
Eddie James3b02e272019-04-22 20:13:55 +000071 void* vgaMem;
72 vgaMem = mmap(nullptr, pageAlignedLength, upstream ? PROT_WRITE : PROT_READ,
73 MAP_SHARED, xdmaFd(), 0);
Tom Josephf8329ac2019-04-11 22:13:22 +053074 if (MAP_FAILED == vgaMem)
75 {
76 rc = -errno;
Eddie James3b02e272019-04-22 20:13:55 +000077 log<level::ERR>("Failed to mmap the XDMA device", entry("RC=%d", rc));
Tom Josephf8329ac2019-04-11 22:13:22 +053078 return rc;
79 }
Eddie James3b02e272019-04-22 20:13:55 +000080
Tom Josephf8329ac2019-04-11 22:13:22 +053081 std::unique_ptr<void, decltype(mmapCleanup)> vgaMemPtr(vgaMem, mmapCleanup);
82
Eddie James3b02e272019-04-22 20:13:55 +000083 if (upstream)
Tom Josephf8329ac2019-04-11 22:13:22 +053084 {
Eddie James3b02e272019-04-22 20:13:55 +000085 std::ifstream stream(path.string());
86
87 stream.seekg(offset);
88 stream.read(static_cast<char*>(vgaMemPtr.get()), length);
89
Tom Joseph7a8a7242019-05-29 15:26:38 +053090 if (static_cast<uint32_t>(stream.gcount()) != length)
Eddie James3b02e272019-04-22 20:13:55 +000091 {
92 log<level::ERR>("mismatch between number of characters to read and "
93 "the length read",
94 entry("LENGTH=%d", length),
95 entry("COUNT=%d", stream.gcount()));
96 return -1;
97 }
Tom Josephf8329ac2019-04-11 22:13:22 +053098 }
99
Eddie James3b02e272019-04-22 20:13:55 +0000100 AspeedXdmaOp xdmaOp;
101 xdmaOp.upstream = upstream ? 1 : 0;
Tom Josephf8329ac2019-04-11 22:13:22 +0530102 xdmaOp.hostAddr = address;
103 xdmaOp.len = length;
104
Eddie James3b02e272019-04-22 20:13:55 +0000105 rc = write(xdmaFd(), &xdmaOp, sizeof(xdmaOp));
Tom Josephf8329ac2019-04-11 22:13:22 +0530106 if (rc < 0)
107 {
108 rc = -errno;
Eddie James3b02e272019-04-22 20:13:55 +0000109 log<level::ERR>("Failed to execute the DMA operation",
110 entry("RC=%d", rc), entry("UPSTREAM=%d", upstream),
Tom Josephf8329ac2019-04-11 22:13:22 +0530111 entry("ADDRESS=%lld", address),
112 entry("LENGTH=%d", length));
113 return rc;
114 }
115
Eddie James3b02e272019-04-22 20:13:55 +0000116 if (!upstream)
117 {
118 std::ofstream stream(path.string());
119
120 stream.seekp(offset);
121 stream.write(static_cast<const char*>(vgaMemPtr.get()), length);
122 }
123
124 return 0;
125}
126
127} // namespace dma
128
Tom Joseph4e48b442019-06-04 09:23:44 +0530129Response readFileIntoMemory(const uint8_t* request, size_t payloadLength)
Tom Josephf8329ac2019-04-11 22:13:22 +0530130{
131 uint32_t fileHandle = 0;
132 uint32_t offset = 0;
133 uint32_t length = 0;
134 uint64_t address = 0;
Eddie James3b02e272019-04-22 20:13:55 +0000135 fs::path path("");
Tom Josephf8329ac2019-04-11 22:13:22 +0530136
Tom Joseph4e48b442019-06-04 09:23:44 +0530137 Response response((sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_RESP_BYTES), 0);
138 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
139
Eddie James3b02e272019-04-22 20:13:55 +0000140 if (payloadLength != PLDM_RW_FILE_MEM_REQ_BYTES)
Tom Josephf8329ac2019-04-11 22:13:22 +0530141 {
Eddie James3b02e272019-04-22 20:13:55 +0000142 encode_rw_file_memory_resp(0, PLDM_READ_FILE_INTO_MEMORY,
Tom Joseph4e48b442019-06-04 09:23:44 +0530143 PLDM_ERROR_INVALID_LENGTH, 0, responsePtr);
144 return response;
Tom Josephf8329ac2019-04-11 22:13:22 +0530145 }
146
Eddie James3b02e272019-04-22 20:13:55 +0000147 decode_rw_file_memory_req(request, payloadLength, &fileHandle, &offset,
148 &length, &address);
Tom Josephf8329ac2019-04-11 22:13:22 +0530149
Tom Josephf8329ac2019-04-11 22:13:22 +0530150 if (!fs::exists(path))
151 {
152 log<level::ERR>("File does not exist", entry("HANDLE=%d", fileHandle));
Eddie James3b02e272019-04-22 20:13:55 +0000153 encode_rw_file_memory_resp(0, PLDM_READ_FILE_INTO_MEMORY,
Tom Joseph4e48b442019-06-04 09:23:44 +0530154 PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
155 return response;
Tom Josephf8329ac2019-04-11 22:13:22 +0530156 }
157
158 auto fileSize = fs::file_size(path);
Tom Josephf8329ac2019-04-11 22:13:22 +0530159 if (offset >= fileSize)
160 {
161 log<level::ERR>("Offset exceeds file size", entry("OFFSET=%d", offset),
162 entry("FILE_SIZE=%d", fileSize));
Eddie James3b02e272019-04-22 20:13:55 +0000163 encode_rw_file_memory_resp(0, PLDM_READ_FILE_INTO_MEMORY,
Tom Joseph4e48b442019-06-04 09:23:44 +0530164 PLDM_DATA_OUT_OF_RANGE, 0, responsePtr);
165 return response;
Tom Josephf8329ac2019-04-11 22:13:22 +0530166 }
167
168 if (offset + length > fileSize)
169 {
170 length = fileSize - offset;
171 }
172
173 if (length % dma::minSize)
174 {
Eddie James3b02e272019-04-22 20:13:55 +0000175 log<level::ERR>("Read length is not a multiple of DMA minSize",
Tom Josephf8329ac2019-04-11 22:13:22 +0530176 entry("LENGTH=%d", length));
Eddie James3b02e272019-04-22 20:13:55 +0000177 encode_rw_file_memory_resp(0, PLDM_READ_FILE_INTO_MEMORY,
Tom Joseph4e48b442019-06-04 09:23:44 +0530178 PLDM_INVALID_READ_LENGTH, 0, responsePtr);
179 return response;
Tom Josephf8329ac2019-04-11 22:13:22 +0530180 }
181
Tom Joseph55306762019-05-02 09:11:26 +0530182 using namespace dma;
183 DMA intf;
Tom Joseph4e48b442019-06-04 09:23:44 +0530184 return transferAll<DMA>(&intf, PLDM_READ_FILE_INTO_MEMORY, path, offset,
185 length, address, true);
Eddie James3b02e272019-04-22 20:13:55 +0000186}
Tom Josephf8329ac2019-04-11 22:13:22 +0530187
Tom Joseph4e48b442019-06-04 09:23:44 +0530188Response writeFileFromMemory(const uint8_t* request, size_t payloadLength)
Eddie James3b02e272019-04-22 20:13:55 +0000189{
190 uint32_t fileHandle = 0;
191 uint32_t offset = 0;
192 uint32_t length = 0;
193 uint64_t address = 0;
194 fs::path path("");
195
Tom Joseph4e48b442019-06-04 09:23:44 +0530196 Response response(sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_RESP_BYTES, 0);
197 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
198
Eddie James3b02e272019-04-22 20:13:55 +0000199 if (payloadLength != PLDM_RW_FILE_MEM_REQ_BYTES)
Tom Josephf8329ac2019-04-11 22:13:22 +0530200 {
Eddie James3b02e272019-04-22 20:13:55 +0000201 encode_rw_file_memory_resp(0, PLDM_WRITE_FILE_FROM_MEMORY,
Tom Joseph4e48b442019-06-04 09:23:44 +0530202 PLDM_ERROR_INVALID_LENGTH, 0, responsePtr);
203 return response;
Tom Josephf8329ac2019-04-11 22:13:22 +0530204 }
Eddie James3b02e272019-04-22 20:13:55 +0000205
206 decode_rw_file_memory_req(request, payloadLength, &fileHandle, &offset,
207 &length, &address);
208
209 if (length % dma::minSize)
210 {
211 log<level::ERR>("Write length is not a multiple of DMA minSize",
212 entry("LENGTH=%d", length));
213 encode_rw_file_memory_resp(0, PLDM_WRITE_FILE_FROM_MEMORY,
Tom Joseph4e48b442019-06-04 09:23:44 +0530214 PLDM_INVALID_WRITE_LENGTH, 0, responsePtr);
215 return response;
Eddie James3b02e272019-04-22 20:13:55 +0000216 }
217
218 if (!fs::exists(path))
219 {
220 log<level::ERR>("File does not exist", entry("HANDLE=%d", fileHandle));
221 encode_rw_file_memory_resp(0, PLDM_WRITE_FILE_FROM_MEMORY,
Tom Joseph4e48b442019-06-04 09:23:44 +0530222 PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
223 return response;
Eddie James3b02e272019-04-22 20:13:55 +0000224 }
225
226 auto fileSize = fs::file_size(path);
227 if (offset >= fileSize)
228 {
229 log<level::ERR>("Offset exceeds file size", entry("OFFSET=%d", offset),
230 entry("FILE_SIZE=%d", fileSize));
231 encode_rw_file_memory_resp(0, PLDM_WRITE_FILE_FROM_MEMORY,
Tom Joseph4e48b442019-06-04 09:23:44 +0530232 PLDM_DATA_OUT_OF_RANGE, 0, responsePtr);
233 return response;
Eddie James3b02e272019-04-22 20:13:55 +0000234 }
235
Tom Joseph55306762019-05-02 09:11:26 +0530236 using namespace dma;
237 DMA intf;
Tom Joseph4e48b442019-06-04 09:23:44 +0530238 return transferAll<DMA>(&intf, PLDM_WRITE_FILE_FROM_MEMORY, path, offset,
239 length, address, false);
Tom Josephf8329ac2019-04-11 22:13:22 +0530240}
241
242} // namespace responder
243} // namespace pldm