1 #include "file_io.hpp"
2
3 #include "file_io_by_type.hpp"
4 #include "file_table.hpp"
5 #include "utils.hpp"
6 #include "xyz/openbmc_project/Common/error.hpp"
7
8 #include <fcntl.h>
9 #include <libpldm/base.h>
10 #include <sys/mman.h>
11 #include <sys/stat.h>
12 #include <sys/types.h>
13 #include <unistd.h>
14
15 #include <phosphor-logging/lg2.hpp>
16
17 #include <cstring>
18 #include <fstream>
19 #include <memory>
20
21 PHOSPHOR_LOG2_USING;
22
23 namespace pldm
24 {
25 using namespace pldm::responder::utils;
26 using namespace sdbusplus::xyz::openbmc_project::Common::Error;
27
28 namespace responder
29 {
30 namespace fs = std::filesystem;
31
32 namespace dma
33 {
34 /** @struct AspeedXdmaOp
35 *
36 * Structure representing XDMA operation
37 */
38 struct AspeedXdmaOp
39 {
40 uint64_t hostAddr; //!< the DMA address on the host side, configured by
41 //!< PCI subsystem.
42 uint32_t len; //!< the size of the transfer in bytes, it should be a
43 //!< multiple of 16 bytes
44 uint32_t upstream; //!< boolean indicating the direction of the DMA
45 //!< operation, true means a transfer from BMC to host.
46 };
47
48 constexpr auto xdmaDev = "/dev/aspeed-xdma";
49
transferHostDataToSocket(int fd,uint32_t length,uint64_t address)50 int DMA::transferHostDataToSocket(int fd, uint32_t length, uint64_t address)
51 {
52 static const size_t pageSize = getpagesize();
53 uint32_t numPages = length / pageSize;
54 uint32_t pageAlignedLength = numPages * pageSize;
55
56 if (length > pageAlignedLength)
57 {
58 pageAlignedLength += pageSize;
59 }
60
61 auto mmapCleanup = [pageAlignedLength](void* vgaMem) {
62 munmap(vgaMem, pageAlignedLength);
63 };
64
65 int dmaFd = -1;
66 int rc = 0;
67 dmaFd = open(xdmaDev, O_RDWR);
68 if (dmaFd < 0)
69 {
70 rc = -errno;
71 error(
72 "Failed to open the XDMA device for transferring remote terminus data to socket with response code '{RC}'",
73 "RC", rc);
74 return rc;
75 }
76
77 pldm::utils::CustomFD xdmaFd(dmaFd);
78
79 void* vgaMem;
80 vgaMem = mmap(nullptr, pageAlignedLength, PROT_READ, MAP_SHARED, xdmaFd(),
81 0);
82 if (MAP_FAILED == vgaMem)
83 {
84 rc = -errno;
85 error(
86 "Failed to mmap the XDMA device for transferring remote terminus data to socket with response code '{RC}'",
87 "RC", rc);
88 return rc;
89 }
90
91 std::unique_ptr<void, decltype(mmapCleanup)> vgaMemPtr(vgaMem, mmapCleanup);
92
93 AspeedXdmaOp xdmaOp;
94 xdmaOp.upstream = 0;
95 xdmaOp.hostAddr = address;
96 xdmaOp.len = length;
97
98 rc = write(xdmaFd(), &xdmaOp, sizeof(xdmaOp));
99 if (rc < 0)
100 {
101 rc = -errno;
102 error(
103 "Failed to execute the DMA operation for transferring remote terminus data to socket at address '{ADDRESS}' and length '{LENGTH}' with response code '{RC}'",
104 "RC", rc, "ADDRESS", address, "LENGTH", length);
105 return rc;
106 }
107
108 rc = writeToUnixSocket(fd, static_cast<const char*>(vgaMemPtr.get()),
109 length);
110 if (rc < 0)
111 {
112 rc = -errno;
113 close(fd);
114 error(
115 "Failed to write to Unix socket, closing socket for transferring remote terminus data to socket with response code '{RC}'",
116 "RC", rc);
117 return rc;
118 }
119 return 0;
120 }
121
transferDataHost(int fd,uint32_t offset,uint32_t length,uint64_t address,bool upstream)122 int DMA::transferDataHost(int fd, uint32_t offset, uint32_t length,
123 uint64_t address, bool upstream)
124 {
125 static const size_t pageSize = getpagesize();
126 uint32_t numPages = length / pageSize;
127 uint32_t pageAlignedLength = numPages * pageSize;
128
129 if (length > pageAlignedLength)
130 {
131 pageAlignedLength += pageSize;
132 }
133
134 int rc = 0;
135 auto mmapCleanup = [pageAlignedLength, &rc](void* vgaMem) {
136 if (rc != -EINTR)
137 {
138 munmap(vgaMem, pageAlignedLength);
139 }
140 else
141 {
142 error(
143 "Received interrupt during DMA transfer for data between BMC and remote terminus. Skipping Unmap.");
144 }
145 };
146
147 int dmaFd = -1;
148 dmaFd = open(xdmaDev, O_RDWR);
149 if (dmaFd < 0)
150 {
151 rc = -errno;
152 error(
153 "Failed to open the XDMA device for data transfer between BMC and remote terminus with response code '{RC}'",
154 "RC", rc);
155 return rc;
156 }
157
158 pldm::utils::CustomFD xdmaFd(dmaFd);
159
160 void* vgaMem;
161 vgaMem = mmap(nullptr, pageAlignedLength, upstream ? PROT_WRITE : PROT_READ,
162 MAP_SHARED, xdmaFd(), 0);
163 if (MAP_FAILED == vgaMem)
164 {
165 rc = -errno;
166 error(
167 "Failed to mmap the XDMA device for data transfer between BMC and remote terminus with response code '{RC}'",
168 "RC", rc);
169 return rc;
170 }
171
172 std::unique_ptr<void, decltype(mmapCleanup)> vgaMemPtr(vgaMem, mmapCleanup);
173
174 if (upstream)
175 {
176 rc = lseek(fd, offset, SEEK_SET);
177 if (rc == -1)
178 {
179 error(
180 "Failed to transfer data between BMC and remote terminus due to lseek failure with upstream '{UPSTREAM}' at offset '{OFFSET}', error number - {ERROR_NUM}",
181 "ERROR_NUM", errno, "UPSTREAM", upstream, "OFFSET", offset);
182 return rc;
183 }
184
185 // Writing to the VGA memory should be aligned at page boundary,
186 // otherwise write data into a buffer aligned at page boundary and
187 // then write to the VGA memory.
188 std::vector<char> buffer{};
189 buffer.resize(pageAlignedLength);
190 rc = read(fd, buffer.data(), length);
191 if (rc == -1)
192 {
193 error(
194 "Failed to transfer data between BMC and remote terminus with file read on upstream '{UPSTREAM}' of length '{LENGTH}' at offset '{OFFSET}' failed, error number - {ERROR_NUM}",
195 "ERROR_NUM", errno, "UPSTREAM", upstream, "LENGTH", length,
196 "OFFSET", offset);
197 return rc;
198 }
199 if (rc != static_cast<int>(length))
200 {
201 error(
202 "Failed to transfer data between BMC and remote terminus mismatched for number of characters to read on upstream '{UPSTREAM}' and the length '{LENGTH}' read and count '{RC}'",
203 "UPSTREAM", upstream, "LENGTH", length, "RC", rc);
204 return -1;
205 }
206 memcpy(static_cast<char*>(vgaMemPtr.get()), buffer.data(),
207 pageAlignedLength);
208 }
209
210 AspeedXdmaOp xdmaOp;
211 xdmaOp.upstream = upstream ? 1 : 0;
212 xdmaOp.hostAddr = address;
213 xdmaOp.len = length;
214
215 rc = write(xdmaFd(), &xdmaOp, sizeof(xdmaOp));
216 if (rc < 0)
217 {
218 rc = -errno;
219 error(
220 "Failed to execute the DMA operation on data between BMC and remote terminus for upstream '{UPSTREAM}' of length '{LENGTH}' at address '{ADDRESS}', response code '{RC}'",
221 "RC", rc, "UPSTREAM", upstream, "ADDRESS", address, "LENGTH",
222 length);
223 return rc;
224 }
225
226 if (!upstream)
227 {
228 rc = lseek(fd, offset, SEEK_SET);
229 if (rc == -1)
230 {
231 error(
232 "Failed to transfer data between BMC and remote terminus due to lseek failure '{UPSTREAM}' at offset '{OFFSET}' failed, error number - {ERROR_NUM}",
233 "ERROR_NUM", errno, "UPSTREAM", upstream, "OFFSET", offset);
234 return rc;
235 }
236 rc = write(fd, static_cast<const char*>(vgaMemPtr.get()), length);
237 if (rc == -1)
238 {
239 error(
240 "Failed to transfer data between BMC and remote terminus where file write upstream '{UPSTREAM}' of length '{LENGTH}' at offset '{OFFSET}' failed, error number - {ERROR_NUM}",
241 "ERROR_NUM", errno, "UPSTREAM", upstream, "LENGTH", length,
242 "OFFSET", offset);
243 return rc;
244 }
245 }
246
247 return 0;
248 }
249
250 } // namespace dma
251
252 namespace oem_ibm
253 {
encodeRWResponseHandler(uint8_t instance_id,uint8_t command,uint8_t completion_code,uint32_t length,struct pldm_msg * msg)254 void encodeRWResponseHandler(uint8_t instance_id, uint8_t command,
255 uint8_t completion_code, uint32_t length,
256 struct pldm_msg* msg)
257 {
258 int rc = encode_rw_file_memory_resp(instance_id, command, completion_code,
259 length, msg);
260 if (rc != PLDM_SUCCESS)
261 {
262 error(
263 "Failed to encode response for command {COMMAND}, response code '{RC}'",
264 "COMMAND", command, "RC", rc);
265 }
266 }
267
encodeReadResponseHandler(uint8_t instance_id,uint8_t completion_code,uint32_t length,struct pldm_msg * msg)268 void encodeReadResponseHandler(uint8_t instance_id, uint8_t completion_code,
269 uint32_t length, struct pldm_msg* msg)
270 {
271 int rc = encode_read_file_resp(instance_id, completion_code, length, msg);
272 if (rc != PLDM_SUCCESS)
273 {
274 error("Failed to encode read file response, response code '{RC}'", "RC",
275 rc);
276 }
277 }
278
encodeWriteResponseHandler(uint8_t instance_id,uint8_t completion_code,uint32_t length,struct pldm_msg * msg)279 void encodeWriteResponseHandler(uint8_t instance_id, uint8_t completion_code,
280 uint32_t length, struct pldm_msg* msg)
281 {
282 int rc = encode_write_file_resp(instance_id, completion_code, length, msg);
283 if (rc != PLDM_SUCCESS)
284 {
285 error("Failed to encode write file response, response code '{RC}'",
286 "RC", rc);
287 }
288 }
289
encodeGetFileResponseHandler(uint8_t instance_id,uint8_t completion_code,uint32_t next_transfer_handle,uint8_t transfer_flag,const uint8_t * table_data,size_t table_size,struct pldm_msg * msg)290 void encodeGetFileResponseHandler(uint8_t instance_id, uint8_t completion_code,
291 uint32_t next_transfer_handle,
292 uint8_t transfer_flag,
293 const uint8_t* table_data, size_t table_size,
294 struct pldm_msg* msg)
295 {
296 int rc = encode_get_file_table_resp(instance_id, completion_code,
297 next_transfer_handle, transfer_flag,
298 table_data, table_size, msg);
299 if (rc != PLDM_SUCCESS)
300 {
301 error("Failed to encode get file table response, response code '{RC}'",
302 "RC", rc);
303 }
304 }
305
encodeRWTypeMemoryResponseHandler(uint8_t instance_id,uint8_t command,uint8_t completion_code,uint32_t length,struct pldm_msg * msg)306 void encodeRWTypeMemoryResponseHandler(uint8_t instance_id, uint8_t command,
307 uint8_t completion_code, uint32_t length,
308 struct pldm_msg* msg)
309 {
310 int rc = encode_rw_file_by_type_memory_resp(instance_id, command,
311 completion_code, length, msg);
312 if (rc != PLDM_SUCCESS)
313 {
314 error(
315 "Failed to encode read/write file by type memory response, response code '{RC}'",
316 "RC", rc);
317 }
318 }
319
encodeRWTypeResponseHandler(uint8_t instance_id,uint8_t command,uint8_t completion_code,uint32_t length,struct pldm_msg * msg)320 void encodeRWTypeResponseHandler(uint8_t instance_id, uint8_t command,
321 uint8_t completion_code, uint32_t length,
322 struct pldm_msg* msg)
323 {
324 int rc = encode_rw_file_by_type_resp(instance_id, command, completion_code,
325 length, msg);
326 if (rc != PLDM_SUCCESS)
327 {
328 error(
329 "Failed to encode response for command {COMMAND}, response code '{RC}'",
330 "COMMAND", command, "RC", rc);
331 }
332 }
333
encodeFileAckResponseHandler(uint8_t instance_id,uint8_t completion_code,struct pldm_msg * msg)334 void encodeFileAckResponseHandler(uint8_t instance_id, uint8_t completion_code,
335 struct pldm_msg* msg)
336 {
337 int rc = encode_file_ack_resp(instance_id, completion_code, msg);
338 if (rc != PLDM_SUCCESS)
339 {
340 error("Failed to encode file ack response, response code '{RC}'", "RC",
341 rc);
342 }
343 }
344
readFileIntoMemory(const pldm_msg * request,size_t payloadLength)345 Response Handler::readFileIntoMemory(const pldm_msg* request,
346 size_t payloadLength)
347 {
348 uint32_t fileHandle = 0;
349 uint32_t offset = 0;
350 uint32_t length = 0;
351 uint64_t address = 0;
352
353 Response response((sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_RESP_BYTES), 0);
354 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
355 if (payloadLength != PLDM_RW_FILE_MEM_REQ_BYTES)
356 {
357 error(
358 "Failed to read file into memory as payload length '{LENGTH}' not equal to '{REQ_LENGTH}'",
359 "LENGTH", payloadLength, "REQ_LENGTH", PLDM_RW_FILE_MEM_REQ_BYTES);
360 encodeRWResponseHandler(request->hdr.instance_id,
361 PLDM_READ_FILE_INTO_MEMORY,
362 PLDM_ERROR_INVALID_LENGTH, 0, responsePtr);
363 return response;
364 }
365
366 int responseCode = decode_rw_file_memory_req(
367 request, payloadLength, &fileHandle, &offset, &length, &address);
368 if (responseCode != PLDM_SUCCESS)
369 {
370 error(
371 "Failed to decode read file into memory request, response code '{RC}'",
372 "RC", responseCode);
373 }
374
375 using namespace pldm::filetable;
376 auto& table = buildFileTable(FILE_TABLE_JSON);
377 FileEntry value{};
378
379 try
380 {
381 value = table.at(fileHandle);
382 }
383 catch (const std::exception& e)
384 {
385 error(
386 "File handle '{HANDLE}' does not exist in the file table, error - {ERROR}",
387 "HANDLE", fileHandle, "ERROR", e);
388 encodeRWResponseHandler(request->hdr.instance_id,
389 PLDM_READ_FILE_INTO_MEMORY,
390 PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
391 return response;
392 }
393
394 if (!fs::exists(value.fsPath))
395 {
396 error("File '{PATH}' and handle '{FILE_HANDLE}' with does not exist",
397 "PATH", value.fsPath, "FILE_HANDLE", fileHandle);
398 encodeRWResponseHandler(request->hdr.instance_id,
399 PLDM_READ_FILE_INTO_MEMORY,
400 PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
401 return response;
402 }
403
404 auto fileSize = fs::file_size(value.fsPath);
405 if (!fileSize)
406 {
407 error(
408 "Failed to PLDM_READ_FILE_INTO_MEMORY from file {PATH} with size '{SIZE}'",
409 "PATH", value.fsPath, "SIZE", fileSize);
410 encodeRWResponseHandler(request->hdr.instance_id,
411 PLDM_READ_FILE_INTO_MEMORY,
412 PLDM_DATA_OUT_OF_RANGE, 0, responsePtr);
413 return response;
414 }
415 if (offset >= fileSize)
416 {
417 error(
418 "Offset '{OFFSET}' exceeds file size '{SIZE}' and file handle '{FILE_HANDLE}'",
419 "OFFSET", offset, "SIZE", fileSize, "FILE_HANDLE", fileHandle);
420 encodeRWResponseHandler(request->hdr.instance_id,
421 PLDM_READ_FILE_INTO_MEMORY,
422 PLDM_DATA_OUT_OF_RANGE, 0, responsePtr);
423 return response;
424 }
425
426 if (offset + length > fileSize)
427 {
428 length = fileSize - offset;
429 }
430
431 if (!length || length % dma::minSize)
432 {
433 error("Packet length '{LENGTH}' is non multiple of minimum DMA size",
434 "LENGTH", length);
435 encodeRWResponseHandler(request->hdr.instance_id,
436 PLDM_READ_FILE_INTO_MEMORY,
437 PLDM_ERROR_INVALID_LENGTH, 0, responsePtr);
438 return response;
439 }
440
441 using namespace dma;
442 DMA intf;
443 return transferAll<DMA>(&intf, PLDM_READ_FILE_INTO_MEMORY, value.fsPath,
444 offset, length, address, true,
445 request->hdr.instance_id);
446 }
447
writeFileFromMemory(const pldm_msg * request,size_t payloadLength)448 Response Handler::writeFileFromMemory(const pldm_msg* request,
449 size_t payloadLength)
450 {
451 uint32_t fileHandle = 0;
452 uint32_t offset = 0;
453 uint32_t length = 0;
454 uint64_t address = 0;
455
456 Response response(sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_RESP_BYTES, 0);
457 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
458
459 if (payloadLength != PLDM_RW_FILE_MEM_REQ_BYTES)
460 {
461 error(
462 "Failed to write file from memory as payload length '{LENGTH}' not equal to '{REQ_LENGTH}'",
463 "LENGTH", payloadLength, "REQ_LENGTH", PLDM_RW_FILE_MEM_REQ_BYTES);
464 encodeRWResponseHandler(request->hdr.instance_id,
465 PLDM_WRITE_FILE_FROM_MEMORY,
466 PLDM_ERROR_INVALID_LENGTH, 0, responsePtr);
467 return response;
468 }
469
470 int responseCode = decode_rw_file_memory_req(
471 request, payloadLength, &fileHandle, &offset, &length, &address);
472 if (responseCode != PLDM_SUCCESS)
473 {
474 error(
475 "Failed to decode write file from memory request, response code '{RC}'",
476 "RC", responseCode);
477 }
478
479 if (!length || length % dma::minSize)
480 {
481 error("Packet length '{LENGTH}' is non multiple of minimum DMA size",
482 "LENGTH", length);
483 encodeRWResponseHandler(request->hdr.instance_id,
484 PLDM_WRITE_FILE_FROM_MEMORY,
485 PLDM_ERROR_INVALID_LENGTH, 0, responsePtr);
486 return response;
487 }
488
489 using namespace pldm::filetable;
490 auto& table = buildFileTable(FILE_TABLE_JSON);
491 FileEntry value{};
492
493 try
494 {
495 value = table.at(fileHandle);
496 }
497 catch (const std::exception& e)
498 {
499 error(
500 "File handle '{HANDLE}' does not exist in the file table, error - {ERROR}",
501 "HANDLE", fileHandle, "ERROR", e);
502 encodeRWResponseHandler(request->hdr.instance_id,
503 PLDM_WRITE_FILE_FROM_MEMORY,
504 PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
505 return response;
506 }
507
508 if (!fs::exists(value.fsPath))
509 {
510 error("File '{PATH}' does not exist for file handle '{FILE_HANDLE}'",
511 "PATH", value.fsPath, "FILE_HANDLE", fileHandle);
512 encodeRWResponseHandler(request->hdr.instance_id,
513 PLDM_WRITE_FILE_FROM_MEMORY,
514 PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
515 return response;
516 }
517
518 auto fileSize = fs::file_size(value.fsPath);
519 if (!fileSize)
520 {
521 info(
522 "File '{PATH}' has size '{SIZE}' for command PLDM_WRITE_FILE_FROM_MEMORY",
523 "PATH", value.fsPath, "SIZE", fileSize);
524 }
525 if (offset >= fileSize)
526 {
527 error(
528 "Offset '{OFFSET}' exceeds file size {SIZE} for file '{PATH} and handle {FILE_HANDLE}",
529 "OFFSET", offset, "SIZE", fileSize, "PATH", value.fsPath,
530 "FILE_HANDLE", fileHandle);
531 encodeRWResponseHandler(request->hdr.instance_id,
532 PLDM_WRITE_FILE_FROM_MEMORY,
533 PLDM_DATA_OUT_OF_RANGE, 0, responsePtr);
534 return response;
535 }
536
537 using namespace dma;
538 DMA intf;
539 return transferAll<DMA>(&intf, PLDM_WRITE_FILE_FROM_MEMORY, value.fsPath,
540 offset, length, address, false,
541 request->hdr.instance_id);
542 }
543
getFileTable(const pldm_msg * request,size_t payloadLength)544 Response Handler::getFileTable(const pldm_msg* request, size_t payloadLength)
545 {
546 uint32_t transferHandle = 0;
547 uint8_t transferFlag = 0;
548 uint8_t tableType = 0;
549
550 Response response(sizeof(pldm_msg_hdr) +
551 PLDM_GET_FILE_TABLE_MIN_RESP_BYTES);
552 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
553
554 if (payloadLength != PLDM_GET_FILE_TABLE_REQ_BYTES)
555 {
556 error(
557 "Failed to get file table as payload length '{LENGTH}' not equal to required length '{REQ_LENGTH}'",
558 "LENGTH", payloadLength, "REQ_LENGTH",
559 PLDM_GET_FILE_TABLE_REQ_BYTES);
560 encodeGetFileResponseHandler(request->hdr.instance_id,
561 PLDM_ERROR_INVALID_LENGTH, 0, 0, nullptr,
562 0, responsePtr);
563 return response;
564 }
565
566 auto rc = decode_get_file_table_req(request, payloadLength, &transferHandle,
567 &transferFlag, &tableType);
568 if (rc)
569 {
570 error("Failed to decode get file table request, response code '{RC}'",
571 "RC", rc);
572 encodeGetFileResponseHandler(request->hdr.instance_id, rc, 0, 0,
573 nullptr, 0, responsePtr);
574 return response;
575 }
576
577 if (tableType != PLDM_FILE_ATTRIBUTE_TABLE)
578 {
579 error(
580 "Failed to match table type '{TYPE}' with expected table type '{REQ_TYPE}'",
581 "TYPE", tableType, "REQ_TYPE", PLDM_FILE_ATTRIBUTE_TABLE);
582 encodeGetFileResponseHandler(request->hdr.instance_id,
583 PLDM_INVALID_FILE_TABLE_TYPE, 0, 0,
584 nullptr, 0, responsePtr);
585 return response;
586 }
587
588 using namespace pldm::filetable;
589 auto table = buildFileTable(FILE_TABLE_JSON);
590 auto attrTable = table();
591 response.resize(response.size() + attrTable.size());
592 responsePtr = reinterpret_cast<pldm_msg*>(response.data());
593
594 if (attrTable.empty())
595 {
596 error("PLDM file attribute table is empty");
597 encodeGetFileResponseHandler(request->hdr.instance_id,
598 PLDM_FILE_TABLE_UNAVAILABLE, 0, 0, nullptr,
599 0, responsePtr);
600 return response;
601 }
602
603 encodeGetFileResponseHandler(request->hdr.instance_id, PLDM_SUCCESS, 0,
604 PLDM_START_AND_END, attrTable.data(),
605 attrTable.size(), responsePtr);
606 return response;
607 }
608
readFile(const pldm_msg * request,size_t payloadLength)609 Response Handler::readFile(const pldm_msg* request, size_t payloadLength)
610 {
611 uint32_t fileHandle = 0;
612 uint32_t offset = 0;
613 uint32_t length = 0;
614
615 Response response(sizeof(pldm_msg_hdr) + PLDM_READ_FILE_RESP_BYTES);
616 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
617
618 if (payloadLength != PLDM_READ_FILE_REQ_BYTES)
619 {
620 error(
621 "Failed to read file as payload length '{LENGTH}' not equal to '{REQ_LENGTH}'",
622 "LENGTH", payloadLength, "REQ_LENGTH", PLDM_READ_FILE_REQ_BYTES);
623 encodeReadResponseHandler(request->hdr.instance_id,
624 PLDM_ERROR_INVALID_LENGTH, length,
625 responsePtr);
626 return response;
627 }
628
629 auto rc = decode_read_file_req(request, payloadLength, &fileHandle, &offset,
630 &length);
631
632 if (rc)
633 {
634 error("Failed to decode read file request, response code '{RC}'", "RC",
635 rc);
636 encodeReadResponseHandler(request->hdr.instance_id, rc, 0, responsePtr);
637 return response;
638 }
639
640 using namespace pldm::filetable;
641 auto& table = buildFileTable(FILE_TABLE_JSON);
642 FileEntry value{};
643
644 try
645 {
646 value = table.at(fileHandle);
647 }
648 catch (const std::exception& e)
649 {
650 error(
651 "File handle '{HANDLE}' does not exist in the file table, error - {ERROR}",
652 "HANDLE", fileHandle, "ERROR", e);
653
654 encodeReadResponseHandler(request->hdr.instance_id,
655 PLDM_INVALID_FILE_HANDLE, length,
656 responsePtr);
657 return response;
658 }
659
660 if (!fs::exists(value.fsPath))
661 {
662 error("File '{PATH}' and handle {FILE_HANDLE} does not exist", "PATH",
663 value.fsPath, "FILE_HANDLE", fileHandle);
664 encodeReadResponseHandler(request->hdr.instance_id,
665 PLDM_INVALID_FILE_HANDLE, length,
666 responsePtr);
667 return response;
668 }
669
670 auto fileSize = fs::file_size(value.fsPath);
671 if (!fileSize)
672 {
673 error("Failed to read file {PATH} with size '{SIZE}'", "PATH",
674 value.fsPath, "SIZE", fileSize);
675 encodeRWResponseHandler(request->hdr.instance_id,
676 PLDM_READ_FILE_INTO_MEMORY,
677 PLDM_DATA_OUT_OF_RANGE, 0, responsePtr);
678 return response;
679 }
680
681 if (offset >= fileSize)
682 {
683 error(
684 "Offset '{OFFSET}' exceeds file size '{SIZE}' for file '{PATH}' and file handle '{HANDLE}'",
685 "OFFSET", offset, "SIZE", fileSize, "PATH", value.fsPath, "HANDLE",
686 fileHandle);
687 encodeReadResponseHandler(request->hdr.instance_id,
688 PLDM_DATA_OUT_OF_RANGE, length, responsePtr);
689 return response;
690 }
691
692 if (offset + length > fileSize)
693 {
694 length = fileSize - offset;
695 }
696
697 response.resize(response.size() + length);
698 responsePtr = reinterpret_cast<pldm_msg*>(response.data());
699 auto fileDataPos = reinterpret_cast<char*>(responsePtr);
700 fileDataPos += sizeof(pldm_msg_hdr) + sizeof(uint8_t) + sizeof(length);
701
702 std::ifstream stream(value.fsPath, std::ios::in | std::ios::binary);
703 stream.seekg(offset);
704 stream.read(fileDataPos, length);
705
706 encodeReadResponseHandler(request->hdr.instance_id, PLDM_SUCCESS, length,
707 responsePtr);
708
709 return response;
710 }
711
writeFile(const pldm_msg * request,size_t payloadLength)712 Response Handler::writeFile(const pldm_msg* request, size_t payloadLength)
713 {
714 uint32_t fileHandle = 0;
715 uint32_t offset = 0;
716 uint32_t length = 0;
717 size_t fileDataOffset = 0;
718
719 Response response(sizeof(pldm_msg_hdr) + PLDM_WRITE_FILE_RESP_BYTES);
720 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
721
722 if (payloadLength < PLDM_WRITE_FILE_REQ_BYTES)
723 {
724 error(
725 "Failed to write file as payload length '{LENGTH}' less than '{REQ_LENGTH}'",
726 "LENGTH", payloadLength, "REQ_LENGTH", PLDM_WRITE_FILE_REQ_BYTES);
727 encodeWriteResponseHandler(request->hdr.instance_id,
728 PLDM_ERROR_INVALID_LENGTH, 0, responsePtr);
729 return response;
730 }
731
732 auto rc = decode_write_file_req(request, payloadLength, &fileHandle,
733 &offset, &length, &fileDataOffset);
734
735 if (rc)
736 {
737 error("Failed to decode write file request, response code '{RC}'", "RC",
738 rc);
739 encodeWriteResponseHandler(request->hdr.instance_id, rc, 0,
740 responsePtr);
741 return response;
742 }
743
744 using namespace pldm::filetable;
745 auto& table = buildFileTable(FILE_TABLE_JSON);
746 FileEntry value{};
747
748 try
749 {
750 value = table.at(fileHandle);
751 }
752 catch (const std::exception& e)
753 {
754 error(
755 "File handle '{HANDLE}' does not exist in the file table, error - {ERROR}",
756 "HANDLE", fileHandle, "ERROR", e);
757 encodeWriteResponseHandler(request->hdr.instance_id,
758 PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
759 return response;
760 }
761
762 if (!fs::exists(value.fsPath))
763 {
764 error("File '{PATH}' and handle {FILE_HANDLE} does not exist", "PATH",
765 value.fsPath, "FILE_HANDLE", fileHandle);
766 encodeWriteResponseHandler(request->hdr.instance_id,
767 PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
768 return response;
769 }
770
771 auto fileSize = fs::file_size(value.fsPath);
772
773 if (!fileSize)
774 {
775 info("File {PATH} has size '{SIZE}' for write file command", "PATH",
776 value.fsPath, "SIZE", fileSize);
777 }
778
779 if (offset >= fileSize)
780 {
781 error(
782 "Offset '{OFFSET}' exceeds file size '{SIZE}' for file '{PATH}' and handle {FILE_HANDLE}",
783 "OFFSET", offset, "SIZE", fileSize, "PATH", value.fsPath,
784 "FILE_HANDLE", fileHandle);
785 encodeWriteResponseHandler(request->hdr.instance_id,
786 PLDM_DATA_OUT_OF_RANGE, 0, responsePtr);
787 return response;
788 }
789
790 auto fileDataPos = reinterpret_cast<const char*>(request->payload) +
791 fileDataOffset;
792
793 std::ofstream stream(value.fsPath,
794 std::ios::in | std::ios::out | std::ios::binary);
795 stream.seekp(offset);
796 stream.write(fileDataPos, length);
797
798 encodeWriteResponseHandler(request->hdr.instance_id, PLDM_SUCCESS, length,
799 responsePtr);
800
801 return response;
802 }
803
rwFileByTypeIntoMemory(uint8_t cmd,const pldm_msg * request,size_t payloadLength,oem_platform::Handler * oemPlatformHandler)804 Response rwFileByTypeIntoMemory(uint8_t cmd, const pldm_msg* request,
805 size_t payloadLength,
806 oem_platform::Handler* oemPlatformHandler)
807 {
808 Response response(
809 sizeof(pldm_msg_hdr) + PLDM_RW_FILE_BY_TYPE_MEM_RESP_BYTES, 0);
810 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
811
812 if (payloadLength != PLDM_RW_FILE_BY_TYPE_MEM_REQ_BYTES)
813 {
814 error(
815 "Failed to read file into memory as payload length '{LENGTH}' not equal to '{REQ_LENGTH}'",
816 "LENGTH", payloadLength, "REQ_LENGTH",
817 PLDM_RW_FILE_BY_TYPE_MEM_REQ_BYTES);
818 encodeRWTypeMemoryResponseHandler(request->hdr.instance_id, cmd,
819 PLDM_ERROR_INVALID_LENGTH, 0,
820 responsePtr);
821 return response;
822 }
823
824 uint16_t fileType{};
825 uint32_t fileHandle{};
826 uint32_t offset{};
827 uint32_t length{};
828 uint64_t address{};
829 auto rc = decode_rw_file_by_type_memory_req(request, payloadLength,
830 &fileType, &fileHandle, &offset,
831 &length, &address);
832 if (rc != PLDM_SUCCESS)
833 {
834 error(
835 "Failed to decode read/write file by type memory request, response code '{RC}'",
836 "RC", rc);
837 encodeRWTypeMemoryResponseHandler(request->hdr.instance_id, cmd, rc, 0,
838 responsePtr);
839 return response;
840 }
841 if (!length || length % dma::minSize)
842 {
843 error(
844 "Packet length '{LENGTH}' is non multiple of minimum DMA size for command {CMD}",
845 "LENGTH", length, "CMD", cmd);
846 encodeRWTypeMemoryResponseHandler(request->hdr.instance_id, cmd,
847 PLDM_ERROR_INVALID_LENGTH, 0,
848 responsePtr);
849 return response;
850 }
851
852 std::unique_ptr<FileHandler> handler{};
853 try
854 {
855 handler = getHandlerByType(fileType, fileHandle);
856 }
857 catch (const InternalFailure& e)
858 {
859 error("Unknown file type '{TYPE}', error - {ERROR} ", "TYPE", fileType,
860 "ERROR", e);
861 encodeRWTypeMemoryResponseHandler(request->hdr.instance_id, cmd,
862 PLDM_INVALID_FILE_TYPE, 0,
863 responsePtr);
864 return response;
865 }
866
867 rc = cmd == PLDM_WRITE_FILE_BY_TYPE_FROM_MEMORY
868 ? handler->writeFromMemory(offset, length, address,
869 oemPlatformHandler)
870 : handler->readIntoMemory(offset, length, address,
871 oemPlatformHandler);
872 encodeRWTypeMemoryResponseHandler(request->hdr.instance_id, cmd, rc, length,
873 responsePtr);
874 return response;
875 }
876
writeFileByTypeFromMemory(const pldm_msg * request,size_t payloadLength)877 Response Handler::writeFileByTypeFromMemory(const pldm_msg* request,
878 size_t payloadLength)
879 {
880 return rwFileByTypeIntoMemory(PLDM_WRITE_FILE_BY_TYPE_FROM_MEMORY, request,
881 payloadLength, oemPlatformHandler);
882 }
883
readFileByTypeIntoMemory(const pldm_msg * request,size_t payloadLength)884 Response Handler::readFileByTypeIntoMemory(const pldm_msg* request,
885 size_t payloadLength)
886 {
887 return rwFileByTypeIntoMemory(PLDM_READ_FILE_BY_TYPE_INTO_MEMORY, request,
888 payloadLength, oemPlatformHandler);
889 }
890
writeFileByType(const pldm_msg * request,size_t payloadLength)891 Response Handler::writeFileByType(const pldm_msg* request, size_t payloadLength)
892 {
893 Response response(sizeof(pldm_msg_hdr) + PLDM_RW_FILE_BY_TYPE_RESP_BYTES);
894 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
895
896 if (payloadLength < PLDM_RW_FILE_BY_TYPE_REQ_BYTES)
897 {
898 error(
899 "Failed to write file by type as payload length '{LENGTH}' less than '{REQ_LENGTH}'",
900 "LENGTH", payloadLength, "REQ_LENGTH",
901 PLDM_RW_FILE_BY_TYPE_REQ_BYTES);
902 encodeRWTypeResponseHandler(request->hdr.instance_id,
903 PLDM_WRITE_FILE_BY_TYPE,
904 PLDM_ERROR_INVALID_LENGTH, 0, responsePtr);
905 return response;
906 }
907 uint16_t fileType{};
908 uint32_t fileHandle{};
909 uint32_t offset{};
910 uint32_t length{};
911
912 auto rc = decode_rw_file_by_type_req(request, payloadLength, &fileType,
913 &fileHandle, &offset, &length);
914 if (rc != PLDM_SUCCESS)
915 {
916 error("Failed decoded write file by type request, response code '{RC}'",
917 "RC", rc);
918 encodeRWTypeResponseHandler(request->hdr.instance_id,
919 PLDM_WRITE_FILE_BY_TYPE, rc, 0,
920 responsePtr);
921 return response;
922 }
923
924 std::unique_ptr<FileHandler> handler{};
925 try
926 {
927 handler = getHandlerByType(fileType, fileHandle);
928 }
929 catch (const InternalFailure& e)
930 {
931 error("Unknown file type '{TYPE}', error - {ERROR}", "TYPE", fileType,
932 "ERROR", e);
933 encodeRWTypeResponseHandler(request->hdr.instance_id,
934 PLDM_WRITE_FILE_BY_TYPE,
935 PLDM_INVALID_FILE_TYPE, 0, responsePtr);
936 return response;
937 }
938
939 rc = handler->write(reinterpret_cast<const char*>(
940 request->payload + PLDM_RW_FILE_BY_TYPE_REQ_BYTES),
941 offset, length, oemPlatformHandler);
942 encodeRWTypeResponseHandler(request->hdr.instance_id,
943 PLDM_WRITE_FILE_BY_TYPE, rc, length,
944 responsePtr);
945 return response;
946 }
947
readFileByType(const pldm_msg * request,size_t payloadLength)948 Response Handler::readFileByType(const pldm_msg* request, size_t payloadLength)
949 {
950 Response response(sizeof(pldm_msg_hdr) + PLDM_RW_FILE_BY_TYPE_RESP_BYTES);
951 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
952
953 if (payloadLength != PLDM_RW_FILE_BY_TYPE_REQ_BYTES)
954 {
955 error(
956 "Failed to read file by type as payload length '{LENGTH}' less than '{REQ_LENGTH}'",
957 "LENGTH", payloadLength, "REQ_LENGTH",
958 PLDM_RW_FILE_BY_TYPE_REQ_BYTES);
959 encodeRWTypeResponseHandler(request->hdr.instance_id,
960 PLDM_READ_FILE_BY_TYPE,
961 PLDM_ERROR_INVALID_LENGTH, 0, responsePtr);
962 return response;
963 }
964 uint16_t fileType{};
965 uint32_t fileHandle{};
966 uint32_t offset{};
967 uint32_t length{};
968
969 auto rc = decode_rw_file_by_type_req(request, payloadLength, &fileType,
970 &fileHandle, &offset, &length);
971 if (rc != PLDM_SUCCESS)
972 {
973 error(
974 "Failed to decode read file by type request, response code '{RC}'",
975 "RC", rc);
976 encodeRWTypeResponseHandler(request->hdr.instance_id,
977 PLDM_READ_FILE_BY_TYPE, rc, 0, responsePtr);
978 return response;
979 }
980
981 std::unique_ptr<FileHandler> handler{};
982 try
983 {
984 handler = getHandlerByType(fileType, fileHandle);
985 }
986 catch (const InternalFailure& e)
987 {
988 error("Unknown file type '{TYPE}', error - {ERROR}", "TYPE", fileType,
989 "ERROR", e);
990 encodeRWTypeResponseHandler(request->hdr.instance_id,
991 PLDM_READ_FILE_BY_TYPE,
992 PLDM_INVALID_FILE_TYPE, 0, responsePtr);
993 return response;
994 }
995
996 rc = handler->read(offset, length, response, oemPlatformHandler);
997 responsePtr = reinterpret_cast<pldm_msg*>(response.data());
998 encodeRWTypeResponseHandler(request->hdr.instance_id,
999 PLDM_READ_FILE_BY_TYPE, rc, length,
1000 responsePtr);
1001 return response;
1002 }
1003
fileAck(const pldm_msg * request,size_t payloadLength)1004 Response Handler::fileAck(const pldm_msg* request, size_t payloadLength)
1005 {
1006 Response response(sizeof(pldm_msg_hdr) + PLDM_FILE_ACK_RESP_BYTES);
1007 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
1008
1009 if (payloadLength != PLDM_FILE_ACK_REQ_BYTES)
1010 {
1011 error(
1012 "Failed to do file ack as payload length '{LENGTH}' is less than '{REQ_LENGTH}'",
1013 "LENGTH", payloadLength, "REQ_LENGTH", PLDM_FILE_ACK_REQ_BYTES);
1014 encodeFileAckResponseHandler(request->hdr.instance_id,
1015 PLDM_ERROR_INVALID_LENGTH, responsePtr);
1016 return response;
1017 }
1018 uint16_t fileType{};
1019 uint32_t fileHandle{};
1020 uint8_t fileStatus{};
1021
1022 auto rc = decode_file_ack_req(request, payloadLength, &fileType,
1023 &fileHandle, &fileStatus);
1024 if (rc != PLDM_SUCCESS)
1025 {
1026 encodeFileAckResponseHandler(request->hdr.instance_id, rc, responsePtr);
1027 return response;
1028 }
1029
1030 std::unique_ptr<FileHandler> handler{};
1031 try
1032 {
1033 handler = getHandlerByType(fileType, fileHandle);
1034 }
1035
1036 catch (const InternalFailure& e)
1037 {
1038 error("Unknown file type '{TYPE}', error - {ERROR}", "TYPE", fileType,
1039 "ERROR", e);
1040 encodeFileAckResponseHandler(request->hdr.instance_id,
1041 PLDM_INVALID_FILE_TYPE, responsePtr);
1042 return response;
1043 }
1044
1045 rc = handler->fileAck(fileStatus);
1046 encodeFileAckResponseHandler(request->hdr.instance_id, rc, responsePtr);
1047 return response;
1048 }
1049
getAlertStatus(const pldm_msg * request,size_t payloadLength)1050 Response Handler::getAlertStatus(const pldm_msg* request, size_t payloadLength)
1051 {
1052 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_ALERT_STATUS_RESP_BYTES);
1053 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
1054 if (payloadLength != PLDM_GET_ALERT_STATUS_REQ_BYTES)
1055 {
1056 error(
1057 "Failed to get alert status as payload length '{LENGTH}' is less than '{REQ_LENGTH}'",
1058 "LENGTH", payloadLength, "REQ_LENGTH",
1059 PLDM_GET_ALERT_STATUS_REQ_BYTES);
1060 return CmdHandler::ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH);
1061 }
1062
1063 uint8_t versionId{};
1064
1065 auto rc = decode_get_alert_status_req(request, payloadLength, &versionId);
1066 if (rc != PLDM_SUCCESS)
1067 {
1068 error("Failed to decode get alert status request, response code '{RC}'",
1069 "RC", rc);
1070 return CmdHandler::ccOnlyResponse(request, rc);
1071 }
1072
1073 if (versionId != 0)
1074 {
1075 error(
1076 "Failed to get alert status due to unsupported version ID '{VERSION}'",
1077 "VERSION", versionId);
1078 return CmdHandler::ccOnlyResponse(request,
1079 PLDM_HOST_UNSUPPORTED_FORMAT_VERSION);
1080 }
1081
1082 constexpr uint32_t rackEntry = 0xFF000030;
1083 constexpr uint32_t priCecNode = 0x00008030;
1084 rc = encode_get_alert_status_resp(request->hdr.instance_id, PLDM_SUCCESS,
1085 rackEntry, priCecNode, responsePtr,
1086 PLDM_GET_ALERT_STATUS_RESP_BYTES);
1087 if (rc != PLDM_SUCCESS)
1088 {
1089 error(
1090 "Failed to encode get alert status response, response code '{RC}'",
1091 "RC", rc);
1092 return CmdHandler::ccOnlyResponse(request, rc);
1093 }
1094
1095 return response;
1096 }
1097
newFileAvailable(const pldm_msg * request,size_t payloadLength)1098 Response Handler::newFileAvailable(const pldm_msg* request,
1099 size_t payloadLength)
1100 {
1101 Response response(sizeof(pldm_msg_hdr) + PLDM_NEW_FILE_RESP_BYTES);
1102
1103 if (payloadLength != PLDM_NEW_FILE_REQ_BYTES)
1104 {
1105 error(
1106 "Failed new file available as payload length '{LENGTH}' is less than '{REQ_LENGTH}'",
1107 "LENGTH", payloadLength, "REQ_LENGTH", PLDM_NEW_FILE_REQ_BYTES);
1108 return CmdHandler::ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH);
1109 }
1110 uint16_t fileType{};
1111 uint32_t fileHandle{};
1112 uint64_t length{};
1113
1114 auto rc = decode_new_file_req(request, payloadLength, &fileType,
1115 &fileHandle, &length);
1116
1117 if (rc != PLDM_SUCCESS)
1118 {
1119 error("Failed to decode new file request, response code '{RC}'", "RC",
1120 rc);
1121 return CmdHandler::ccOnlyResponse(request, rc);
1122 }
1123
1124 std::unique_ptr<FileHandler> handler{};
1125 try
1126 {
1127 handler = getHandlerByType(fileType, fileHandle);
1128 }
1129 catch (const InternalFailure& e)
1130 {
1131 error("Unknown file type '{TYPE}', error - {ERROR}", "TYPE", fileType,
1132 "ERROR", e);
1133 return CmdHandler::ccOnlyResponse(request, PLDM_INVALID_FILE_TYPE);
1134 }
1135
1136 rc = handler->newFileAvailable(length);
1137 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
1138 int responseCode = encode_new_file_resp(request->hdr.instance_id, rc,
1139 responsePtr);
1140 if (responseCode != PLDM_SUCCESS)
1141 {
1142 error(
1143 "Failed to encode new file available response, response code '{RC}'",
1144 "RC", responseCode);
1145 }
1146 return response;
1147 }
1148
1149 } // namespace oem_ibm
1150 } // namespace responder
1151 } // namespace pldm
1152