blob: 06d683b5ad319effb42129c37a83c815ff3ddf9c [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{
33 uint8_t upstream; //!< boolean indicating the direction of the DMA
34 //!< operation, true means a transfer from BMC to host.
35 uint64_t hostAddr; //!< the DMA address on the host side, configured by
36 //!< PCI subsystem.
37 uint32_t len; //!< the size of the transfer in bytes, it should be a
38 //!< multiple of 16 bytes
39} __attribute__((packed));
40
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
90 if (stream.gcount() != length)
91 {
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 Josephf8329ac2019-04-11 22:13:22 +0530129void readFileIntoMemory(const uint8_t* request, size_t payloadLength,
130 pldm_msg* response)
131{
132 uint32_t fileHandle = 0;
133 uint32_t offset = 0;
134 uint32_t length = 0;
135 uint64_t address = 0;
Eddie James3b02e272019-04-22 20:13:55 +0000136 fs::path path("");
Tom Josephf8329ac2019-04-11 22:13:22 +0530137
Eddie James3b02e272019-04-22 20:13:55 +0000138 if (payloadLength != PLDM_RW_FILE_MEM_REQ_BYTES)
Tom Josephf8329ac2019-04-11 22:13:22 +0530139 {
Eddie James3b02e272019-04-22 20:13:55 +0000140 encode_rw_file_memory_resp(0, PLDM_READ_FILE_INTO_MEMORY,
141 PLDM_ERROR_INVALID_LENGTH, 0, response);
Tom Josephf8329ac2019-04-11 22:13:22 +0530142 return;
143 }
144
Eddie James3b02e272019-04-22 20:13:55 +0000145 decode_rw_file_memory_req(request, payloadLength, &fileHandle, &offset,
146 &length, &address);
Tom Josephf8329ac2019-04-11 22:13:22 +0530147
Tom Josephf8329ac2019-04-11 22:13:22 +0530148 if (!fs::exists(path))
149 {
150 log<level::ERR>("File does not exist", entry("HANDLE=%d", fileHandle));
Eddie James3b02e272019-04-22 20:13:55 +0000151 encode_rw_file_memory_resp(0, PLDM_READ_FILE_INTO_MEMORY,
152 PLDM_INVALID_FILE_HANDLE, 0, response);
Tom Josephf8329ac2019-04-11 22:13:22 +0530153 return;
154 }
155
156 auto fileSize = fs::file_size(path);
Tom Josephf8329ac2019-04-11 22:13:22 +0530157 if (offset >= fileSize)
158 {
159 log<level::ERR>("Offset exceeds file size", entry("OFFSET=%d", offset),
160 entry("FILE_SIZE=%d", fileSize));
Eddie James3b02e272019-04-22 20:13:55 +0000161 encode_rw_file_memory_resp(0, PLDM_READ_FILE_INTO_MEMORY,
162 PLDM_DATA_OUT_OF_RANGE, 0, response);
Tom Josephf8329ac2019-04-11 22:13:22 +0530163 return;
164 }
165
166 if (offset + length > fileSize)
167 {
168 length = fileSize - offset;
169 }
170
171 if (length % dma::minSize)
172 {
Eddie James3b02e272019-04-22 20:13:55 +0000173 log<level::ERR>("Read length is not a multiple of DMA minSize",
Tom Josephf8329ac2019-04-11 22:13:22 +0530174 entry("LENGTH=%d", length));
Eddie James3b02e272019-04-22 20:13:55 +0000175 encode_rw_file_memory_resp(0, PLDM_READ_FILE_INTO_MEMORY,
176 PLDM_INVALID_READ_LENGTH, 0, response);
Tom Josephf8329ac2019-04-11 22:13:22 +0530177 return;
178 }
179
Tom Joseph55306762019-05-02 09:11:26 +0530180 using namespace dma;
181 DMA intf;
182 transferAll<DMA>(&intf, PLDM_READ_FILE_INTO_MEMORY, path, offset, length,
183 address, true, response);
Eddie James3b02e272019-04-22 20:13:55 +0000184}
Tom Josephf8329ac2019-04-11 22:13:22 +0530185
Eddie James3b02e272019-04-22 20:13:55 +0000186void writeFileFromMemory(const uint8_t* request, size_t payloadLength,
187 pldm_msg* response)
188{
189 uint32_t fileHandle = 0;
190 uint32_t offset = 0;
191 uint32_t length = 0;
192 uint64_t address = 0;
193 fs::path path("");
194
195 if (payloadLength != PLDM_RW_FILE_MEM_REQ_BYTES)
Tom Josephf8329ac2019-04-11 22:13:22 +0530196 {
Eddie James3b02e272019-04-22 20:13:55 +0000197 encode_rw_file_memory_resp(0, PLDM_WRITE_FILE_FROM_MEMORY,
198 PLDM_ERROR_INVALID_LENGTH, 0, response);
199 return;
Tom Josephf8329ac2019-04-11 22:13:22 +0530200 }
Eddie James3b02e272019-04-22 20:13:55 +0000201
202 decode_rw_file_memory_req(request, payloadLength, &fileHandle, &offset,
203 &length, &address);
204
205 if (length % dma::minSize)
206 {
207 log<level::ERR>("Write length is not a multiple of DMA minSize",
208 entry("LENGTH=%d", length));
209 encode_rw_file_memory_resp(0, PLDM_WRITE_FILE_FROM_MEMORY,
210 PLDM_INVALID_WRITE_LENGTH, 0, response);
211 return;
212 }
213
214 if (!fs::exists(path))
215 {
216 log<level::ERR>("File does not exist", entry("HANDLE=%d", fileHandle));
217 encode_rw_file_memory_resp(0, PLDM_WRITE_FILE_FROM_MEMORY,
218 PLDM_INVALID_FILE_HANDLE, 0, response);
219 return;
220 }
221
222 auto fileSize = fs::file_size(path);
223 if (offset >= fileSize)
224 {
225 log<level::ERR>("Offset exceeds file size", entry("OFFSET=%d", offset),
226 entry("FILE_SIZE=%d", fileSize));
227 encode_rw_file_memory_resp(0, PLDM_WRITE_FILE_FROM_MEMORY,
228 PLDM_DATA_OUT_OF_RANGE, 0, response);
229 return;
230 }
231
Tom Joseph55306762019-05-02 09:11:26 +0530232 using namespace dma;
233 DMA intf;
234 transferAll<DMA>(&intf, PLDM_WRITE_FILE_FROM_MEMORY, path, offset, length,
235 address, false, response);
Tom Josephf8329ac2019-04-11 22:13:22 +0530236}
237
238} // namespace responder
239} // namespace pldm