blob: 12b2864c8b56e2818d54be66eb77a7993f13b24c [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 {
Tom Josephb23304a2019-06-19 10:04:00 +053089 std::ifstream stream(path.string(), std::ios::in | std::ios::binary);
Eddie James3b02e272019-04-22 20:13:55 +000090 stream.seekg(offset);
Tom Joseph9b979252019-06-19 09:59:18 +053091
92 // Writing to the VGA memory should be aligned at page boundary,
93 // otherwise write data into a buffer aligned at page boundary and
94 // then write to the VGA memory.
95 std::vector<char> buffer{};
96 buffer.resize(pageAlignedLength);
97 stream.read(buffer.data(), length);
98 memcpy(static_cast<char*>(vgaMemPtr.get()), buffer.data(),
99 pageAlignedLength);
Eddie James3b02e272019-04-22 20:13:55 +0000100
Tom Joseph7a8a7242019-05-29 15:26:38 +0530101 if (static_cast<uint32_t>(stream.gcount()) != length)
Eddie James3b02e272019-04-22 20:13:55 +0000102 {
103 log<level::ERR>("mismatch between number of characters to read and "
104 "the length read",
105 entry("LENGTH=%d", length),
106 entry("COUNT=%d", stream.gcount()));
107 return -1;
108 }
Tom Josephf8329ac2019-04-11 22:13:22 +0530109 }
110
Eddie James3b02e272019-04-22 20:13:55 +0000111 AspeedXdmaOp xdmaOp;
112 xdmaOp.upstream = upstream ? 1 : 0;
Tom Josephf8329ac2019-04-11 22:13:22 +0530113 xdmaOp.hostAddr = address;
114 xdmaOp.len = length;
115
Eddie James3b02e272019-04-22 20:13:55 +0000116 rc = write(xdmaFd(), &xdmaOp, sizeof(xdmaOp));
Tom Josephf8329ac2019-04-11 22:13:22 +0530117 if (rc < 0)
118 {
119 rc = -errno;
Eddie James3b02e272019-04-22 20:13:55 +0000120 log<level::ERR>("Failed to execute the DMA operation",
121 entry("RC=%d", rc), entry("UPSTREAM=%d", upstream),
Tom Josephf8329ac2019-04-11 22:13:22 +0530122 entry("ADDRESS=%lld", address),
123 entry("LENGTH=%d", length));
124 return rc;
125 }
126
Eddie James3b02e272019-04-22 20:13:55 +0000127 if (!upstream)
128 {
Tom Josephb23304a2019-06-19 10:04:00 +0530129 std::ofstream stream(path.string(),
130 std::ios::in | std::ios::out | std::ios::binary);
Eddie James3b02e272019-04-22 20:13:55 +0000131
132 stream.seekp(offset);
133 stream.write(static_cast<const char*>(vgaMemPtr.get()), length);
134 }
135
136 return 0;
137}
138
139} // namespace dma
140
Tom Joseph4e48b442019-06-04 09:23:44 +0530141Response readFileIntoMemory(const uint8_t* request, size_t payloadLength)
Tom Josephf8329ac2019-04-11 22:13:22 +0530142{
143 uint32_t fileHandle = 0;
144 uint32_t offset = 0;
145 uint32_t length = 0;
146 uint64_t address = 0;
147
Tom Joseph4e48b442019-06-04 09:23:44 +0530148 Response response((sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_RESP_BYTES), 0);
149 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
150
Eddie James3b02e272019-04-22 20:13:55 +0000151 if (payloadLength != PLDM_RW_FILE_MEM_REQ_BYTES)
Tom Josephf8329ac2019-04-11 22:13:22 +0530152 {
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_ERROR_INVALID_LENGTH, 0, responsePtr);
155 return response;
Tom Josephf8329ac2019-04-11 22:13:22 +0530156 }
157
Eddie James3b02e272019-04-22 20:13:55 +0000158 decode_rw_file_memory_req(request, payloadLength, &fileHandle, &offset,
159 &length, &address);
Tom Josephf8329ac2019-04-11 22:13:22 +0530160
Tom Joseph07220402019-05-15 16:30:41 +0530161 using namespace pldm::filetable;
162 auto& table = buildFileTable(FILE_TABLE_JSON);
163 FileEntry value{};
164
165 try
166 {
167 value = table.at(fileHandle);
168 }
169 catch (std::exception& e)
170 {
171 log<level::ERR>("File handle does not exist in the file table",
172 entry("HANDLE=%d", fileHandle));
173 encode_rw_file_memory_resp(0, PLDM_READ_FILE_INTO_MEMORY,
174 PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
175 return response;
176 }
177
178 if (!fs::exists(value.fsPath))
Tom Josephf8329ac2019-04-11 22:13:22 +0530179 {
180 log<level::ERR>("File does not exist", entry("HANDLE=%d", fileHandle));
Eddie James3b02e272019-04-22 20:13:55 +0000181 encode_rw_file_memory_resp(0, PLDM_READ_FILE_INTO_MEMORY,
Tom Joseph4e48b442019-06-04 09:23:44 +0530182 PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
183 return response;
Tom Josephf8329ac2019-04-11 22:13:22 +0530184 }
185
Tom Joseph07220402019-05-15 16:30:41 +0530186 auto fileSize = fs::file_size(value.fsPath);
Tom Josephf8329ac2019-04-11 22:13:22 +0530187 if (offset >= fileSize)
188 {
189 log<level::ERR>("Offset exceeds file size", entry("OFFSET=%d", offset),
190 entry("FILE_SIZE=%d", fileSize));
Eddie James3b02e272019-04-22 20:13:55 +0000191 encode_rw_file_memory_resp(0, PLDM_READ_FILE_INTO_MEMORY,
Tom Joseph4e48b442019-06-04 09:23:44 +0530192 PLDM_DATA_OUT_OF_RANGE, 0, responsePtr);
193 return response;
Tom Josephf8329ac2019-04-11 22:13:22 +0530194 }
195
196 if (offset + length > fileSize)
197 {
198 length = fileSize - offset;
199 }
200
201 if (length % dma::minSize)
202 {
Eddie James3b02e272019-04-22 20:13:55 +0000203 log<level::ERR>("Read length is not a multiple of DMA minSize",
Tom Josephf8329ac2019-04-11 22:13:22 +0530204 entry("LENGTH=%d", length));
Eddie James3b02e272019-04-22 20:13:55 +0000205 encode_rw_file_memory_resp(0, PLDM_READ_FILE_INTO_MEMORY,
Tom Joseph4e48b442019-06-04 09:23:44 +0530206 PLDM_INVALID_READ_LENGTH, 0, responsePtr);
207 return response;
Tom Josephf8329ac2019-04-11 22:13:22 +0530208 }
209
Tom Joseph55306762019-05-02 09:11:26 +0530210 using namespace dma;
211 DMA intf;
Tom Joseph07220402019-05-15 16:30:41 +0530212 return transferAll<DMA>(&intf, PLDM_READ_FILE_INTO_MEMORY, value.fsPath,
213 offset, length, address, true);
Eddie James3b02e272019-04-22 20:13:55 +0000214}
Tom Josephf8329ac2019-04-11 22:13:22 +0530215
Tom Joseph4e48b442019-06-04 09:23:44 +0530216Response writeFileFromMemory(const uint8_t* request, size_t payloadLength)
Eddie James3b02e272019-04-22 20:13:55 +0000217{
218 uint32_t fileHandle = 0;
219 uint32_t offset = 0;
220 uint32_t length = 0;
221 uint64_t address = 0;
Eddie James3b02e272019-04-22 20:13:55 +0000222
Tom Joseph4e48b442019-06-04 09:23:44 +0530223 Response response(sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_RESP_BYTES, 0);
224 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
225
Eddie James3b02e272019-04-22 20:13:55 +0000226 if (payloadLength != PLDM_RW_FILE_MEM_REQ_BYTES)
Tom Josephf8329ac2019-04-11 22:13:22 +0530227 {
Eddie James3b02e272019-04-22 20:13:55 +0000228 encode_rw_file_memory_resp(0, PLDM_WRITE_FILE_FROM_MEMORY,
Tom Joseph4e48b442019-06-04 09:23:44 +0530229 PLDM_ERROR_INVALID_LENGTH, 0, responsePtr);
230 return response;
Tom Josephf8329ac2019-04-11 22:13:22 +0530231 }
Eddie James3b02e272019-04-22 20:13:55 +0000232
233 decode_rw_file_memory_req(request, payloadLength, &fileHandle, &offset,
234 &length, &address);
235
236 if (length % dma::minSize)
237 {
238 log<level::ERR>("Write length is not a multiple of DMA minSize",
239 entry("LENGTH=%d", length));
240 encode_rw_file_memory_resp(0, PLDM_WRITE_FILE_FROM_MEMORY,
Tom Joseph4e48b442019-06-04 09:23:44 +0530241 PLDM_INVALID_WRITE_LENGTH, 0, responsePtr);
242 return response;
Eddie James3b02e272019-04-22 20:13:55 +0000243 }
244
Tom Joseph07220402019-05-15 16:30:41 +0530245 using namespace pldm::filetable;
246 auto& table = buildFileTable(FILE_TABLE_JSON);
247 FileEntry value{};
248
249 try
250 {
251 value = table.at(fileHandle);
252 }
253 catch (std::exception& e)
254 {
255 log<level::ERR>("File handle does not exist in the file table",
256 entry("HANDLE=%d", fileHandle));
257 encode_rw_file_memory_resp(0, PLDM_WRITE_FILE_FROM_MEMORY,
258 PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
259 return response;
260 }
261
262 if (!fs::exists(value.fsPath))
Eddie James3b02e272019-04-22 20:13:55 +0000263 {
264 log<level::ERR>("File does not exist", entry("HANDLE=%d", fileHandle));
265 encode_rw_file_memory_resp(0, PLDM_WRITE_FILE_FROM_MEMORY,
Tom Joseph4e48b442019-06-04 09:23:44 +0530266 PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
267 return response;
Eddie James3b02e272019-04-22 20:13:55 +0000268 }
269
Tom Joseph07220402019-05-15 16:30:41 +0530270 auto fileSize = fs::file_size(value.fsPath);
Eddie James3b02e272019-04-22 20:13:55 +0000271 if (offset >= fileSize)
272 {
273 log<level::ERR>("Offset exceeds file size", entry("OFFSET=%d", offset),
274 entry("FILE_SIZE=%d", fileSize));
275 encode_rw_file_memory_resp(0, PLDM_WRITE_FILE_FROM_MEMORY,
Tom Joseph4e48b442019-06-04 09:23:44 +0530276 PLDM_DATA_OUT_OF_RANGE, 0, responsePtr);
277 return response;
Eddie James3b02e272019-04-22 20:13:55 +0000278 }
279
Tom Joseph55306762019-05-02 09:11:26 +0530280 using namespace dma;
281 DMA intf;
Tom Joseph07220402019-05-15 16:30:41 +0530282 return transferAll<DMA>(&intf, PLDM_WRITE_FILE_FROM_MEMORY, value.fsPath,
283 offset, length, address, false);
Tom Josephf8329ac2019-04-11 22:13:22 +0530284}
285
Tom Joseph19856622019-06-07 10:18:21 +0530286Response getFileTable(const uint8_t* request, size_t payloadLength)
287{
288 uint32_t transferHandle = 0;
289 uint8_t transferFlag = 0;
290 uint8_t tableType = 0;
291
292 Response response(sizeof(pldm_msg_hdr) +
293 PLDM_GET_FILE_TABLE_MIN_RESP_BYTES);
294 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
295
296 if (payloadLength != PLDM_GET_FILE_TABLE_REQ_BYTES)
297 {
298 encode_get_file_table_resp(0, PLDM_ERROR_INVALID_LENGTH, 0, 0, nullptr,
299 0, responsePtr);
300 return response;
301 }
302
303 auto rc = decode_get_file_table_req(request, payloadLength, &transferHandle,
304 &transferFlag, &tableType);
305 if (rc)
306 {
307 encode_get_file_table_resp(0, rc, 0, 0, nullptr, 0, responsePtr);
308 return response;
309 }
310
311 if (tableType != PLDM_FILE_ATTRIBUTE_TABLE)
312 {
313 encode_get_file_table_resp(0, PLDM_INVALID_FILE_TABLE_TYPE, 0, 0,
314 nullptr, 0, responsePtr);
315 return response;
316 }
317
318 using namespace pldm::filetable;
319 auto table = buildFileTable(FILE_TABLE_JSON);
320 auto attrTable = table();
321 response.resize(response.size() + attrTable.size());
322 responsePtr = reinterpret_cast<pldm_msg*>(response.data());
323
324 if (attrTable.empty())
325 {
326 encode_get_file_table_resp(0, PLDM_FILE_TABLE_UNAVAILABLE, 0, 0,
327 nullptr, 0, responsePtr);
328 return response;
329 }
330
331 encode_get_file_table_resp(0, PLDM_SUCCESS, 0, PLDM_START_AND_END,
332 attrTable.data(), attrTable.size(), responsePtr);
333 return response;
334}
335
Tom Josephf8329ac2019-04-11 22:13:22 +0530336} // namespace responder
337} // namespace pldm