blob: 24997fbea01966c8de082f5aaf48934c77e1819c [file] [log] [blame]
Tom Joseph0c6d22c2019-06-26 09:58:41 +05301#include "config.h"
2
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +05303#include "file_io.hpp"
4
Tom Joseph0c6d22c2019-06-26 09:58:41 +05305#include "file_table.hpp"
Jinu Joy Thomasf666db12019-05-29 05:22:31 -05006#include "libpldmresponder/utils.hpp"
7#include "registration.hpp"
8
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +05309#include <fcntl.h>
10#include <sys/mman.h>
11#include <sys/stat.h>
12#include <sys/types.h>
13#include <unistd.h>
14
15#include <cstring>
16#include <fstream>
17#include <phosphor-logging/log.hpp>
18
19#include "libpldm/base.h"
20
21namespace pldm
22{
23
24namespace responder
25{
26
Jinu Joy Thomasf666db12019-05-29 05:22:31 -050027namespace oem_ibm
28{
29
30void registerHandlers()
31{
Tom Joseph0c6d22c2019-06-26 09:58:41 +053032 registerHandler(PLDM_OEM, PLDM_GET_FILE_TABLE, std::move(getFileTable));
Jinu Joy Thomasf666db12019-05-29 05:22:31 -050033 registerHandler(PLDM_OEM, PLDM_READ_FILE_INTO_MEMORY,
34 std::move(readFileIntoMemory));
35 registerHandler(PLDM_OEM, PLDM_WRITE_FILE_FROM_MEMORY,
36 std::move(writeFileFromMemory));
vkaverap5b914c32019-06-30 22:23:54 -050037 registerHandler(PLDM_OEM, PLDM_READ_FILE, std::move(readFile));
38 registerHandler(PLDM_OEM, PLDM_WRITE_FILE, std::move(writeFile));
Jinu Joy Thomasf666db12019-05-29 05:22:31 -050039}
40
41} // namespace oem_ibm
42
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +053043namespace fs = std::filesystem;
44using namespace phosphor::logging;
45
46namespace dma
47{
48
49/** @struct AspeedXdmaOp
50 *
51 * Structure representing XDMA operation
52 */
53struct AspeedXdmaOp
54{
55 uint64_t hostAddr; //!< the DMA address on the host side, configured by
56 //!< PCI subsystem.
57 uint32_t len; //!< the size of the transfer in bytes, it should be a
58 //!< multiple of 16 bytes
59 uint32_t upstream; //!< boolean indicating the direction of the DMA
60 //!< operation, true means a transfer from BMC to host.
61};
62
63constexpr auto xdmaDev = "/dev/xdma";
64
65int DMA::transferDataHost(const fs::path& path, uint32_t offset,
66 uint32_t length, uint64_t address, bool upstream)
67{
68 static const size_t pageSize = getpagesize();
69 uint32_t numPages = length / pageSize;
70 uint32_t pageAlignedLength = numPages * pageSize;
71
72 if (length > pageAlignedLength)
73 {
74 pageAlignedLength += pageSize;
75 }
76
77 auto mmapCleanup = [pageAlignedLength](void* vgaMem) {
78 munmap(vgaMem, pageAlignedLength);
79 };
80
81 int fd = -1;
82 int rc = 0;
83 fd = open(xdmaDev, O_RDWR);
84 if (fd < 0)
85 {
86 rc = -errno;
87 log<level::ERR>("Failed to open the XDMA device", entry("RC=%d", rc));
88 return rc;
89 }
90
91 utils::CustomFD xdmaFd(fd);
92
93 void* vgaMem;
94 vgaMem = mmap(nullptr, pageAlignedLength, upstream ? PROT_WRITE : PROT_READ,
95 MAP_SHARED, xdmaFd(), 0);
96 if (MAP_FAILED == vgaMem)
97 {
98 rc = -errno;
99 log<level::ERR>("Failed to mmap the XDMA device", entry("RC=%d", rc));
100 return rc;
101 }
102
103 std::unique_ptr<void, decltype(mmapCleanup)> vgaMemPtr(vgaMem, mmapCleanup);
104
105 if (upstream)
106 {
Tom Joseph0c6d22c2019-06-26 09:58:41 +0530107 std::ifstream stream(path.string(), std::ios::in | std::ios::binary);
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530108 stream.seekg(offset);
Tom Joseph0c6d22c2019-06-26 09:58:41 +0530109
110 // Writing to the VGA memory should be aligned at page boundary,
111 // otherwise write data into a buffer aligned at page boundary and
112 // then write to the VGA memory.
113 std::vector<char> buffer{};
114 buffer.resize(pageAlignedLength);
115 stream.read(buffer.data(), length);
116 memcpy(static_cast<char*>(vgaMemPtr.get()), buffer.data(),
117 pageAlignedLength);
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530118
119 if (static_cast<uint32_t>(stream.gcount()) != length)
120 {
121 log<level::ERR>("mismatch between number of characters to read and "
122 "the length read",
123 entry("LENGTH=%d", length),
124 entry("COUNT=%d", stream.gcount()));
125 return -1;
126 }
127 }
128
129 AspeedXdmaOp xdmaOp;
130 xdmaOp.upstream = upstream ? 1 : 0;
131 xdmaOp.hostAddr = address;
132 xdmaOp.len = length;
133
134 rc = write(xdmaFd(), &xdmaOp, sizeof(xdmaOp));
135 if (rc < 0)
136 {
137 rc = -errno;
138 log<level::ERR>("Failed to execute the DMA operation",
139 entry("RC=%d", rc), entry("UPSTREAM=%d", upstream),
140 entry("ADDRESS=%lld", address),
141 entry("LENGTH=%d", length));
142 return rc;
143 }
144
145 if (!upstream)
146 {
Tom Joseph0c6d22c2019-06-26 09:58:41 +0530147 std::ofstream stream(path.string(),
148 std::ios::in | std::ios::out | std::ios::binary);
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530149
150 stream.seekp(offset);
151 stream.write(static_cast<const char*>(vgaMemPtr.get()), length);
152 }
153
154 return 0;
155}
156
157} // namespace dma
158
Jinu Joy Thomasf666db12019-05-29 05:22:31 -0500159Response readFileIntoMemory(const pldm_msg* request, size_t payloadLength)
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530160{
161 uint32_t fileHandle = 0;
162 uint32_t offset = 0;
163 uint32_t length = 0;
164 uint64_t address = 0;
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530165
166 Response response((sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_RESP_BYTES), 0);
167 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
168
169 if (payloadLength != PLDM_RW_FILE_MEM_REQ_BYTES)
170 {
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +0530171 encode_rw_file_memory_resp(request->hdr.instance_id,
172 PLDM_READ_FILE_INTO_MEMORY,
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530173 PLDM_ERROR_INVALID_LENGTH, 0, responsePtr);
174 return response;
175 }
176
Zahed Hossain223a73d2019-07-04 12:46:18 -0500177 decode_rw_file_memory_req(request, payloadLength, &fileHandle, &offset,
178 &length, &address);
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530179
Tom Joseph0c6d22c2019-06-26 09:58:41 +0530180 using namespace pldm::filetable;
181 auto& table = buildFileTable(FILE_TABLE_JSON);
182 FileEntry value{};
183
184 try
185 {
186 value = table.at(fileHandle);
187 }
188 catch (std::exception& e)
189 {
190 log<level::ERR>("File handle does not exist in the file table",
191 entry("HANDLE=%d", fileHandle));
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +0530192 encode_rw_file_memory_resp(request->hdr.instance_id,
193 PLDM_READ_FILE_INTO_MEMORY,
Tom Joseph0c6d22c2019-06-26 09:58:41 +0530194 PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
195 return response;
196 }
197
198 if (!fs::exists(value.fsPath))
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530199 {
200 log<level::ERR>("File does not exist", entry("HANDLE=%d", fileHandle));
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +0530201 encode_rw_file_memory_resp(request->hdr.instance_id,
202 PLDM_READ_FILE_INTO_MEMORY,
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530203 PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
204 return response;
205 }
206
Tom Joseph0c6d22c2019-06-26 09:58:41 +0530207 auto fileSize = fs::file_size(value.fsPath);
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530208 if (offset >= fileSize)
209 {
210 log<level::ERR>("Offset exceeds file size", entry("OFFSET=%d", offset),
211 entry("FILE_SIZE=%d", fileSize));
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +0530212 encode_rw_file_memory_resp(request->hdr.instance_id,
213 PLDM_READ_FILE_INTO_MEMORY,
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530214 PLDM_DATA_OUT_OF_RANGE, 0, responsePtr);
215 return response;
216 }
217
218 if (offset + length > fileSize)
219 {
220 length = fileSize - offset;
221 }
222
223 if (length % dma::minSize)
224 {
225 log<level::ERR>("Read length is not a multiple of DMA minSize",
226 entry("LENGTH=%d", length));
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +0530227 encode_rw_file_memory_resp(request->hdr.instance_id,
228 PLDM_READ_FILE_INTO_MEMORY,
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530229 PLDM_INVALID_READ_LENGTH, 0, responsePtr);
230 return response;
231 }
232
233 using namespace dma;
234 DMA intf;
Tom Joseph0c6d22c2019-06-26 09:58:41 +0530235 return transferAll<DMA>(&intf, PLDM_READ_FILE_INTO_MEMORY, value.fsPath,
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +0530236 offset, length, address, true,
237 request->hdr.instance_id);
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530238}
239
Jinu Joy Thomasf666db12019-05-29 05:22:31 -0500240Response writeFileFromMemory(const pldm_msg* request, size_t payloadLength)
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530241{
242 uint32_t fileHandle = 0;
243 uint32_t offset = 0;
244 uint32_t length = 0;
245 uint64_t address = 0;
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530246
247 Response response(sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_RESP_BYTES, 0);
248 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
249
250 if (payloadLength != PLDM_RW_FILE_MEM_REQ_BYTES)
251 {
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +0530252 encode_rw_file_memory_resp(request->hdr.instance_id,
253 PLDM_WRITE_FILE_FROM_MEMORY,
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530254 PLDM_ERROR_INVALID_LENGTH, 0, responsePtr);
255 return response;
256 }
257
Zahed Hossain223a73d2019-07-04 12:46:18 -0500258 decode_rw_file_memory_req(request, payloadLength, &fileHandle, &offset,
259 &length, &address);
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530260
261 if (length % dma::minSize)
262 {
263 log<level::ERR>("Write length is not a multiple of DMA minSize",
264 entry("LENGTH=%d", length));
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +0530265 encode_rw_file_memory_resp(request->hdr.instance_id,
266 PLDM_WRITE_FILE_FROM_MEMORY,
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530267 PLDM_INVALID_WRITE_LENGTH, 0, responsePtr);
268 return response;
269 }
270
Tom Joseph0c6d22c2019-06-26 09:58:41 +0530271 using namespace pldm::filetable;
272 auto& table = buildFileTable(FILE_TABLE_JSON);
273 FileEntry value{};
274
275 try
276 {
277 value = table.at(fileHandle);
278 }
279 catch (std::exception& e)
280 {
281 log<level::ERR>("File handle does not exist in the file table",
282 entry("HANDLE=%d", fileHandle));
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +0530283 encode_rw_file_memory_resp(request->hdr.instance_id,
284 PLDM_WRITE_FILE_FROM_MEMORY,
Tom Joseph0c6d22c2019-06-26 09:58:41 +0530285 PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
286 return response;
287 }
288
289 if (!fs::exists(value.fsPath))
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530290 {
291 log<level::ERR>("File does not exist", entry("HANDLE=%d", fileHandle));
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +0530292 encode_rw_file_memory_resp(request->hdr.instance_id,
293 PLDM_WRITE_FILE_FROM_MEMORY,
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530294 PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
295 return response;
296 }
297
Tom Joseph0c6d22c2019-06-26 09:58:41 +0530298 auto fileSize = fs::file_size(value.fsPath);
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530299 if (offset >= fileSize)
300 {
301 log<level::ERR>("Offset exceeds file size", entry("OFFSET=%d", offset),
302 entry("FILE_SIZE=%d", fileSize));
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +0530303 encode_rw_file_memory_resp(request->hdr.instance_id,
304 PLDM_WRITE_FILE_FROM_MEMORY,
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530305 PLDM_DATA_OUT_OF_RANGE, 0, responsePtr);
306 return response;
307 }
308
309 using namespace dma;
310 DMA intf;
Tom Joseph0c6d22c2019-06-26 09:58:41 +0530311 return transferAll<DMA>(&intf, PLDM_WRITE_FILE_FROM_MEMORY, value.fsPath,
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +0530312 offset, length, address, false,
313 request->hdr.instance_id);
Tom Joseph0c6d22c2019-06-26 09:58:41 +0530314}
315
316Response getFileTable(const pldm_msg* request, size_t payloadLength)
317{
318 uint32_t transferHandle = 0;
319 uint8_t transferFlag = 0;
320 uint8_t tableType = 0;
321
322 Response response(sizeof(pldm_msg_hdr) +
323 PLDM_GET_FILE_TABLE_MIN_RESP_BYTES);
324 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
325
326 if (payloadLength != PLDM_GET_FILE_TABLE_REQ_BYTES)
327 {
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +0530328 encode_get_file_table_resp(request->hdr.instance_id,
329 PLDM_ERROR_INVALID_LENGTH, 0, 0, nullptr, 0,
330 responsePtr);
Tom Joseph0c6d22c2019-06-26 09:58:41 +0530331 return response;
332 }
333
Zahed Hossain223a73d2019-07-04 12:46:18 -0500334 auto rc = decode_get_file_table_req(request, payloadLength, &transferHandle,
335 &transferFlag, &tableType);
Tom Joseph0c6d22c2019-06-26 09:58:41 +0530336 if (rc)
337 {
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +0530338 encode_get_file_table_resp(request->hdr.instance_id, rc, 0, 0, nullptr,
339 0, responsePtr);
Tom Joseph0c6d22c2019-06-26 09:58:41 +0530340 return response;
341 }
342
343 if (tableType != PLDM_FILE_ATTRIBUTE_TABLE)
344 {
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +0530345 encode_get_file_table_resp(request->hdr.instance_id,
346 PLDM_INVALID_FILE_TABLE_TYPE, 0, 0, nullptr,
347 0, responsePtr);
Tom Joseph0c6d22c2019-06-26 09:58:41 +0530348 return response;
349 }
350
351 using namespace pldm::filetable;
352 auto table = buildFileTable(FILE_TABLE_JSON);
353 auto attrTable = table();
354 response.resize(response.size() + attrTable.size());
355 responsePtr = reinterpret_cast<pldm_msg*>(response.data());
356
357 if (attrTable.empty())
358 {
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +0530359 encode_get_file_table_resp(request->hdr.instance_id,
360 PLDM_FILE_TABLE_UNAVAILABLE, 0, 0, nullptr,
361 0, responsePtr);
Tom Joseph0c6d22c2019-06-26 09:58:41 +0530362 return response;
363 }
364
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +0530365 encode_get_file_table_resp(request->hdr.instance_id, PLDM_SUCCESS, 0,
366 PLDM_START_AND_END, attrTable.data(),
367 attrTable.size(), responsePtr);
Tom Joseph0c6d22c2019-06-26 09:58:41 +0530368 return response;
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530369}
370
vkaverap5b914c32019-06-30 22:23:54 -0500371Response readFile(const pldm_msg* request, size_t payloadLength)
372{
373 uint32_t fileHandle = 0;
374 uint32_t offset = 0;
375 uint32_t length = 0;
376
377 Response response(sizeof(pldm_msg_hdr) + PLDM_READ_FILE_RESP_BYTES);
378 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
379
380 if (payloadLength != PLDM_READ_FILE_REQ_BYTES)
381 {
382 encode_read_file_resp(request->hdr.instance_id,
383 PLDM_ERROR_INVALID_LENGTH, length, responsePtr);
384 return response;
385 }
386
387 auto rc = decode_read_file_req(request, payloadLength, &fileHandle, &offset,
388 &length);
389
390 if (rc)
391 {
392 encode_read_file_resp(request->hdr.instance_id, rc, 0, responsePtr);
393 return response;
394 }
395
396 using namespace pldm::filetable;
397 auto& table = buildFileTable(FILE_TABLE_JSON);
398 FileEntry value{};
399
400 try
401 {
402 value = table.at(fileHandle);
403 }
404 catch (std::exception& e)
405 {
406 log<level::ERR>("File handle does not exist in the file table",
407 entry("HANDLE=%d", fileHandle));
408 encode_read_file_resp(request->hdr.instance_id,
409 PLDM_INVALID_FILE_HANDLE, length, responsePtr);
410 return response;
411 }
412
413 if (!fs::exists(value.fsPath))
414 {
415 log<level::ERR>("File does not exist", entry("HANDLE=%d", fileHandle));
416 encode_read_file_resp(request->hdr.instance_id,
417 PLDM_INVALID_FILE_HANDLE, length, responsePtr);
418 return response;
419 }
420
421 auto fileSize = fs::file_size(value.fsPath);
422 if (offset >= fileSize)
423 {
424 log<level::ERR>("Offset exceeds file size", entry("OFFSET=%d", offset),
425 entry("FILE_SIZE=%d", fileSize));
426 encode_read_file_resp(request->hdr.instance_id, PLDM_DATA_OUT_OF_RANGE,
427 length, responsePtr);
428 return response;
429 }
430
431 if (offset + length > fileSize)
432 {
433 length = fileSize - offset;
434 }
435
436 response.resize(response.size() + length);
437 responsePtr = reinterpret_cast<pldm_msg*>(response.data());
438 auto fileDataPos = reinterpret_cast<char*>(responsePtr);
439 fileDataPos += sizeof(pldm_msg_hdr) + sizeof(uint8_t) + sizeof(length);
440
441 std::ifstream stream(value.fsPath, std::ios::in | std::ios::binary);
442 stream.seekg(offset);
443 stream.read(fileDataPos, length);
444
445 encode_read_file_resp(request->hdr.instance_id, PLDM_SUCCESS, length,
446 responsePtr);
447
448 return response;
449}
450
451Response writeFile(const pldm_msg* request, size_t payloadLength)
452{
453 uint32_t fileHandle = 0;
454 uint32_t offset = 0;
455 uint32_t length = 0;
456 size_t fileDataOffset = 0;
457
458 Response response(sizeof(pldm_msg_hdr) + PLDM_WRITE_FILE_RESP_BYTES);
459 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
460
461 if (payloadLength < PLDM_WRITE_FILE_REQ_BYTES)
462 {
463 encode_write_file_resp(request->hdr.instance_id,
464 PLDM_ERROR_INVALID_LENGTH, 0, responsePtr);
465 return response;
466 }
467
468 auto rc = decode_write_file_req(request, payloadLength, &fileHandle,
469 &offset, &length, &fileDataOffset);
470
471 if (rc)
472 {
473 encode_write_file_resp(request->hdr.instance_id, rc, 0, responsePtr);
474 return response;
475 }
476
477 using namespace pldm::filetable;
478 auto& table = buildFileTable(FILE_TABLE_JSON);
479 FileEntry value{};
480
481 try
482 {
483 value = table.at(fileHandle);
484 }
485 catch (std::exception& e)
486 {
487 log<level::ERR>("File handle does not exist in the file table",
488 entry("HANDLE=%d", fileHandle));
489 encode_write_file_resp(request->hdr.instance_id,
490 PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
491 return response;
492 }
493
494 if (!fs::exists(value.fsPath))
495 {
496 log<level::ERR>("File does not exist", entry("HANDLE=%d", fileHandle));
497 encode_write_file_resp(request->hdr.instance_id,
498 PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
499 return response;
500 }
501
502 auto fileSize = fs::file_size(value.fsPath);
503 if (offset >= fileSize)
504 {
505 log<level::ERR>("Offset exceeds file size", entry("OFFSET=%d", offset),
506 entry("FILE_SIZE=%d", fileSize));
507 encode_write_file_resp(request->hdr.instance_id, PLDM_DATA_OUT_OF_RANGE,
508 0, responsePtr);
509 return response;
510 }
511
512 auto fileDataPos =
513 reinterpret_cast<const char*>(request->payload) + fileDataOffset;
514
515 std::ofstream stream(value.fsPath,
516 std::ios::in | std::ios::out | std::ios::binary);
517 stream.seekp(offset);
518 stream.write(fileDataPos, length);
519
520 encode_write_file_resp(request->hdr.instance_id, PLDM_SUCCESS, length,
521 responsePtr);
522
523 return response;
524}
525
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530526} // namespace responder
527} // namespace pldm