blob: a6c9fae36c669624569ee645dcf7e3858ec19df0 [file] [log] [blame]
Tom Joseph07220402019-05-15 16:30:41 +05301#include "config.h"
2
Tom Josephf8329ac2019-04-11 22:13:22 +05303#include "file_io.hpp"
4
Tom Joseph07220402019-05-15 16:30:41 +05305#include "file_table.hpp"
6
Tom Josephf8329ac2019-04-11 22:13:22 +05307#include <fcntl.h>
8#include <sys/mman.h>
9#include <sys/stat.h>
10#include <sys/types.h>
11#include <unistd.h>
12
13#include <cstring>
14#include <fstream>
15#include <phosphor-logging/log.hpp>
16
17#include "libpldm/base.h"
18
19namespace pldm
20{
21
22namespace responder
23{
24
25namespace fs = std::filesystem;
26using namespace phosphor::logging;
27
Eddie James3b02e272019-04-22 20:13:55 +000028namespace dma
Tom Josephf8329ac2019-04-11 22:13:22 +053029{
Eddie James3b02e272019-04-22 20:13:55 +000030
31/** @struct AspeedXdmaOp
32 *
33 * Structure representing XDMA operation
34 */
35struct AspeedXdmaOp
36{
Eddie James3b02e272019-04-22 20:13:55 +000037 uint64_t hostAddr; //!< the DMA address on the host side, configured by
38 //!< PCI subsystem.
39 uint32_t len; //!< the size of the transfer in bytes, it should be a
40 //!< multiple of 16 bytes
Eddie Jamesc6da21e2019-05-29 18:29:58 +000041 uint32_t upstream; //!< boolean indicating the direction of the DMA
42 //!< operation, true means a transfer from BMC to host.
43};
Eddie James3b02e272019-04-22 20:13:55 +000044
45constexpr auto xdmaDev = "/dev/xdma";
46
Tom Joseph55306762019-05-02 09:11:26 +053047int DMA::transferDataHost(const fs::path& path, uint32_t offset,
48 uint32_t length, uint64_t address, bool upstream)
Eddie James3b02e272019-04-22 20:13:55 +000049{
Tom Josephf8329ac2019-04-11 22:13:22 +053050 static const size_t pageSize = getpagesize();
51 uint32_t numPages = length / pageSize;
Eddie James3b02e272019-04-22 20:13:55 +000052 uint32_t pageAlignedLength = numPages * pageSize;
53
54 if (length > pageAlignedLength)
Tom Josephf8329ac2019-04-11 22:13:22 +053055 {
Eddie James3b02e272019-04-22 20:13:55 +000056 pageAlignedLength += pageSize;
Tom Josephf8329ac2019-04-11 22:13:22 +053057 }
58
Eddie James3b02e272019-04-22 20:13:55 +000059 auto mmapCleanup = [pageAlignedLength](void* vgaMem) {
60 munmap(vgaMem, pageAlignedLength);
Tom Josephf8329ac2019-04-11 22:13:22 +053061 };
62
63 int fd = -1;
64 int rc = 0;
Eddie James3b02e272019-04-22 20:13:55 +000065 fd = open(xdmaDev, O_RDWR);
Tom Josephf8329ac2019-04-11 22:13:22 +053066 if (fd < 0)
67 {
Eddie James3b02e272019-04-22 20:13:55 +000068 rc = -errno;
69 log<level::ERR>("Failed to open the XDMA device", entry("RC=%d", rc));
Tom Josephf8329ac2019-04-11 22:13:22 +053070 return rc;
71 }
Tom Josephf8329ac2019-04-11 22:13:22 +053072
Eddie James3b02e272019-04-22 20:13:55 +000073 utils::CustomFD xdmaFd(fd);
Tom Josephf8329ac2019-04-11 22:13:22 +053074
Eddie James3b02e272019-04-22 20:13:55 +000075 void* vgaMem;
76 vgaMem = mmap(nullptr, pageAlignedLength, upstream ? PROT_WRITE : PROT_READ,
77 MAP_SHARED, xdmaFd(), 0);
Tom Josephf8329ac2019-04-11 22:13:22 +053078 if (MAP_FAILED == vgaMem)
79 {
80 rc = -errno;
Eddie James3b02e272019-04-22 20:13:55 +000081 log<level::ERR>("Failed to mmap the XDMA device", entry("RC=%d", rc));
Tom Josephf8329ac2019-04-11 22:13:22 +053082 return rc;
83 }
Eddie James3b02e272019-04-22 20:13:55 +000084
Tom Josephf8329ac2019-04-11 22:13:22 +053085 std::unique_ptr<void, decltype(mmapCleanup)> vgaMemPtr(vgaMem, mmapCleanup);
86
Eddie James3b02e272019-04-22 20:13:55 +000087 if (upstream)
Tom Josephf8329ac2019-04-11 22:13:22 +053088 {
Eddie James3b02e272019-04-22 20:13:55 +000089 std::ifstream stream(path.string());
90
91 stream.seekg(offset);
92 stream.read(static_cast<char*>(vgaMemPtr.get()), length);
93
Tom Joseph7a8a7242019-05-29 15:26:38 +053094 if (static_cast<uint32_t>(stream.gcount()) != length)
Eddie James3b02e272019-04-22 20:13:55 +000095 {
96 log<level::ERR>("mismatch between number of characters to read and "
97 "the length read",
98 entry("LENGTH=%d", length),
99 entry("COUNT=%d", stream.gcount()));
100 return -1;
101 }
Tom Josephf8329ac2019-04-11 22:13:22 +0530102 }
103
Eddie James3b02e272019-04-22 20:13:55 +0000104 AspeedXdmaOp xdmaOp;
105 xdmaOp.upstream = upstream ? 1 : 0;
Tom Josephf8329ac2019-04-11 22:13:22 +0530106 xdmaOp.hostAddr = address;
107 xdmaOp.len = length;
108
Eddie James3b02e272019-04-22 20:13:55 +0000109 rc = write(xdmaFd(), &xdmaOp, sizeof(xdmaOp));
Tom Josephf8329ac2019-04-11 22:13:22 +0530110 if (rc < 0)
111 {
112 rc = -errno;
Eddie James3b02e272019-04-22 20:13:55 +0000113 log<level::ERR>("Failed to execute the DMA operation",
114 entry("RC=%d", rc), entry("UPSTREAM=%d", upstream),
Tom Josephf8329ac2019-04-11 22:13:22 +0530115 entry("ADDRESS=%lld", address),
116 entry("LENGTH=%d", length));
117 return rc;
118 }
119
Eddie James3b02e272019-04-22 20:13:55 +0000120 if (!upstream)
121 {
122 std::ofstream stream(path.string());
123
124 stream.seekp(offset);
125 stream.write(static_cast<const char*>(vgaMemPtr.get()), length);
126 }
127
128 return 0;
129}
130
131} // namespace dma
132
Tom Joseph4e48b442019-06-04 09:23:44 +0530133Response readFileIntoMemory(const uint8_t* request, size_t payloadLength)
Tom Josephf8329ac2019-04-11 22:13:22 +0530134{
135 uint32_t fileHandle = 0;
136 uint32_t offset = 0;
137 uint32_t length = 0;
138 uint64_t address = 0;
139
Tom Joseph4e48b442019-06-04 09:23:44 +0530140 Response response((sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_RESP_BYTES), 0);
141 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
142
Eddie James3b02e272019-04-22 20:13:55 +0000143 if (payloadLength != PLDM_RW_FILE_MEM_REQ_BYTES)
Tom Josephf8329ac2019-04-11 22:13:22 +0530144 {
Eddie James3b02e272019-04-22 20:13:55 +0000145 encode_rw_file_memory_resp(0, PLDM_READ_FILE_INTO_MEMORY,
Tom Joseph4e48b442019-06-04 09:23:44 +0530146 PLDM_ERROR_INVALID_LENGTH, 0, responsePtr);
147 return response;
Tom Josephf8329ac2019-04-11 22:13:22 +0530148 }
149
Eddie James3b02e272019-04-22 20:13:55 +0000150 decode_rw_file_memory_req(request, payloadLength, &fileHandle, &offset,
151 &length, &address);
Tom Josephf8329ac2019-04-11 22:13:22 +0530152
Tom Joseph07220402019-05-15 16:30:41 +0530153 using namespace pldm::filetable;
154 auto& table = buildFileTable(FILE_TABLE_JSON);
155 FileEntry value{};
156
157 try
158 {
159 value = table.at(fileHandle);
160 }
161 catch (std::exception& e)
162 {
163 log<level::ERR>("File handle does not exist in the file table",
164 entry("HANDLE=%d", fileHandle));
165 encode_rw_file_memory_resp(0, PLDM_READ_FILE_INTO_MEMORY,
166 PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
167 return response;
168 }
169
170 if (!fs::exists(value.fsPath))
Tom Josephf8329ac2019-04-11 22:13:22 +0530171 {
172 log<level::ERR>("File does not exist", entry("HANDLE=%d", fileHandle));
Eddie James3b02e272019-04-22 20:13:55 +0000173 encode_rw_file_memory_resp(0, PLDM_READ_FILE_INTO_MEMORY,
Tom Joseph4e48b442019-06-04 09:23:44 +0530174 PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
175 return response;
Tom Josephf8329ac2019-04-11 22:13:22 +0530176 }
177
Tom Joseph07220402019-05-15 16:30:41 +0530178 auto fileSize = fs::file_size(value.fsPath);
Tom Josephf8329ac2019-04-11 22:13:22 +0530179 if (offset >= fileSize)
180 {
181 log<level::ERR>("Offset exceeds file size", entry("OFFSET=%d", offset),
182 entry("FILE_SIZE=%d", fileSize));
Eddie James3b02e272019-04-22 20:13:55 +0000183 encode_rw_file_memory_resp(0, PLDM_READ_FILE_INTO_MEMORY,
Tom Joseph4e48b442019-06-04 09:23:44 +0530184 PLDM_DATA_OUT_OF_RANGE, 0, responsePtr);
185 return response;
Tom Josephf8329ac2019-04-11 22:13:22 +0530186 }
187
188 if (offset + length > fileSize)
189 {
190 length = fileSize - offset;
191 }
192
193 if (length % dma::minSize)
194 {
Eddie James3b02e272019-04-22 20:13:55 +0000195 log<level::ERR>("Read length is not a multiple of DMA minSize",
Tom Josephf8329ac2019-04-11 22:13:22 +0530196 entry("LENGTH=%d", length));
Eddie James3b02e272019-04-22 20:13:55 +0000197 encode_rw_file_memory_resp(0, PLDM_READ_FILE_INTO_MEMORY,
Tom Joseph4e48b442019-06-04 09:23:44 +0530198 PLDM_INVALID_READ_LENGTH, 0, responsePtr);
199 return response;
Tom Josephf8329ac2019-04-11 22:13:22 +0530200 }
201
Tom Joseph55306762019-05-02 09:11:26 +0530202 using namespace dma;
203 DMA intf;
Tom Joseph07220402019-05-15 16:30:41 +0530204 return transferAll<DMA>(&intf, PLDM_READ_FILE_INTO_MEMORY, value.fsPath,
205 offset, length, address, true);
Eddie James3b02e272019-04-22 20:13:55 +0000206}
Tom Josephf8329ac2019-04-11 22:13:22 +0530207
Tom Joseph4e48b442019-06-04 09:23:44 +0530208Response writeFileFromMemory(const uint8_t* request, size_t payloadLength)
Eddie James3b02e272019-04-22 20:13:55 +0000209{
210 uint32_t fileHandle = 0;
211 uint32_t offset = 0;
212 uint32_t length = 0;
213 uint64_t address = 0;
Eddie James3b02e272019-04-22 20:13:55 +0000214
Tom Joseph4e48b442019-06-04 09:23:44 +0530215 Response response(sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_RESP_BYTES, 0);
216 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
217
Eddie James3b02e272019-04-22 20:13:55 +0000218 if (payloadLength != PLDM_RW_FILE_MEM_REQ_BYTES)
Tom Josephf8329ac2019-04-11 22:13:22 +0530219 {
Eddie James3b02e272019-04-22 20:13:55 +0000220 encode_rw_file_memory_resp(0, PLDM_WRITE_FILE_FROM_MEMORY,
Tom Joseph4e48b442019-06-04 09:23:44 +0530221 PLDM_ERROR_INVALID_LENGTH, 0, responsePtr);
222 return response;
Tom Josephf8329ac2019-04-11 22:13:22 +0530223 }
Eddie James3b02e272019-04-22 20:13:55 +0000224
225 decode_rw_file_memory_req(request, payloadLength, &fileHandle, &offset,
226 &length, &address);
227
228 if (length % dma::minSize)
229 {
230 log<level::ERR>("Write length is not a multiple of DMA minSize",
231 entry("LENGTH=%d", length));
232 encode_rw_file_memory_resp(0, PLDM_WRITE_FILE_FROM_MEMORY,
Tom Joseph4e48b442019-06-04 09:23:44 +0530233 PLDM_INVALID_WRITE_LENGTH, 0, responsePtr);
234 return response;
Eddie James3b02e272019-04-22 20:13:55 +0000235 }
236
Tom Joseph07220402019-05-15 16:30:41 +0530237 using namespace pldm::filetable;
238 auto& table = buildFileTable(FILE_TABLE_JSON);
239 FileEntry value{};
240
241 try
242 {
243 value = table.at(fileHandle);
244 }
245 catch (std::exception& e)
246 {
247 log<level::ERR>("File handle does not exist in the file table",
248 entry("HANDLE=%d", fileHandle));
249 encode_rw_file_memory_resp(0, PLDM_WRITE_FILE_FROM_MEMORY,
250 PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
251 return response;
252 }
253
254 if (!fs::exists(value.fsPath))
Eddie James3b02e272019-04-22 20:13:55 +0000255 {
256 log<level::ERR>("File does not exist", entry("HANDLE=%d", fileHandle));
257 encode_rw_file_memory_resp(0, PLDM_WRITE_FILE_FROM_MEMORY,
Tom Joseph4e48b442019-06-04 09:23:44 +0530258 PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
259 return response;
Eddie James3b02e272019-04-22 20:13:55 +0000260 }
261
Tom Joseph07220402019-05-15 16:30:41 +0530262 auto fileSize = fs::file_size(value.fsPath);
Eddie James3b02e272019-04-22 20:13:55 +0000263 if (offset >= fileSize)
264 {
265 log<level::ERR>("Offset exceeds file size", entry("OFFSET=%d", offset),
266 entry("FILE_SIZE=%d", fileSize));
267 encode_rw_file_memory_resp(0, PLDM_WRITE_FILE_FROM_MEMORY,
Tom Joseph4e48b442019-06-04 09:23:44 +0530268 PLDM_DATA_OUT_OF_RANGE, 0, responsePtr);
269 return response;
Eddie James3b02e272019-04-22 20:13:55 +0000270 }
271
Tom Joseph55306762019-05-02 09:11:26 +0530272 using namespace dma;
273 DMA intf;
Tom Joseph07220402019-05-15 16:30:41 +0530274 return transferAll<DMA>(&intf, PLDM_WRITE_FILE_FROM_MEMORY, value.fsPath,
275 offset, length, address, false);
Tom Josephf8329ac2019-04-11 22:13:22 +0530276}
277
Tom Joseph19856622019-06-07 10:18:21 +0530278Response getFileTable(const uint8_t* request, size_t payloadLength)
279{
280 uint32_t transferHandle = 0;
281 uint8_t transferFlag = 0;
282 uint8_t tableType = 0;
283
284 Response response(sizeof(pldm_msg_hdr) +
285 PLDM_GET_FILE_TABLE_MIN_RESP_BYTES);
286 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
287
288 if (payloadLength != PLDM_GET_FILE_TABLE_REQ_BYTES)
289 {
290 encode_get_file_table_resp(0, PLDM_ERROR_INVALID_LENGTH, 0, 0, nullptr,
291 0, responsePtr);
292 return response;
293 }
294
295 auto rc = decode_get_file_table_req(request, payloadLength, &transferHandle,
296 &transferFlag, &tableType);
297 if (rc)
298 {
299 encode_get_file_table_resp(0, rc, 0, 0, nullptr, 0, responsePtr);
300 return response;
301 }
302
303 if (tableType != PLDM_FILE_ATTRIBUTE_TABLE)
304 {
305 encode_get_file_table_resp(0, PLDM_INVALID_FILE_TABLE_TYPE, 0, 0,
306 nullptr, 0, responsePtr);
307 return response;
308 }
309
310 using namespace pldm::filetable;
311 auto table = buildFileTable(FILE_TABLE_JSON);
312 auto attrTable = table();
313 response.resize(response.size() + attrTable.size());
314 responsePtr = reinterpret_cast<pldm_msg*>(response.data());
315
316 if (attrTable.empty())
317 {
318 encode_get_file_table_resp(0, PLDM_FILE_TABLE_UNAVAILABLE, 0, 0,
319 nullptr, 0, responsePtr);
320 return response;
321 }
322
323 encode_get_file_table_resp(0, PLDM_SUCCESS, 0, PLDM_START_AND_END,
324 attrTable.data(), attrTable.size(), responsePtr);
325 return response;
326}
327
Tom Josephf8329ac2019-04-11 22:13:22 +0530328} // namespace responder
329} // namespace pldm