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 =
81 mmap(nullptr, pageAlignedLength, PROT_READ, MAP_SHARED, xdmaFd(), 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(
291 uint8_t instance_id, uint8_t completion_code, uint32_t next_transfer_handle,
292 uint8_t transfer_flag, const uint8_t* table_data, size_t table_size,
293 struct pldm_msg* msg)
294 {
295 int rc = encode_get_file_table_resp(instance_id, completion_code,
296 next_transfer_handle, transfer_flag,
297 table_data, table_size, msg);
298 if (rc != PLDM_SUCCESS)
299 {
300 error("Failed to encode get file table response, response code '{RC}'",
301 "RC", rc);
302 }
303 }
304
encodeRWTypeMemoryResponseHandler(uint8_t instance_id,uint8_t command,uint8_t completion_code,uint32_t length,struct pldm_msg * msg)305 void encodeRWTypeMemoryResponseHandler(uint8_t instance_id, uint8_t command,
306 uint8_t completion_code, uint32_t length,
307 struct pldm_msg* msg)
308 {
309 int rc = encode_rw_file_by_type_memory_resp(instance_id, command,
310 completion_code, length, msg);
311 if (rc != PLDM_SUCCESS)
312 {
313 error(
314 "Failed to encode read/write file by type memory response, response code '{RC}'",
315 "RC", rc);
316 }
317 }
318
encodeRWTypeResponseHandler(uint8_t instance_id,uint8_t command,uint8_t completion_code,uint32_t length,struct pldm_msg * msg)319 void encodeRWTypeResponseHandler(uint8_t instance_id, uint8_t command,
320 uint8_t completion_code, uint32_t length,
321 struct pldm_msg* msg)
322 {
323 int rc = encode_rw_file_by_type_resp(instance_id, command, completion_code,
324 length, msg);
325 if (rc != PLDM_SUCCESS)
326 {
327 error(
328 "Failed to encode response for command {COMMAND}, response code '{RC}'",
329 "COMMAND", command, "RC", rc);
330 }
331 }
332
encodeFileAckResponseHandler(uint8_t instance_id,uint8_t completion_code,struct pldm_msg * msg)333 void encodeFileAckResponseHandler(uint8_t instance_id, uint8_t completion_code,
334 struct pldm_msg* msg)
335 {
336 int rc = encode_file_ack_resp(instance_id, completion_code, msg);
337 if (rc != PLDM_SUCCESS)
338 {
339 error("Failed to encode file ack response, response code '{RC}'", "RC",
340 rc);
341 }
342 }
343
readFileIntoMemory(const pldm_msg * request,size_t payloadLength)344 Response Handler::readFileIntoMemory(const pldm_msg* request,
345 size_t payloadLength)
346 {
347 uint32_t fileHandle = 0;
348 uint32_t offset = 0;
349 uint32_t length = 0;
350 uint64_t address = 0;
351
352 Response response((sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_RESP_BYTES), 0);
353 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
354 if (payloadLength != PLDM_RW_FILE_MEM_REQ_BYTES)
355 {
356 error(
357 "Failed to read file into memory as payload length '{LENGTH}' not equal to '{REQ_LENGTH}'",
358 "LENGTH", payloadLength, "REQ_LENGTH", PLDM_RW_FILE_MEM_REQ_BYTES);
359 encodeRWResponseHandler(request->hdr.instance_id,
360 PLDM_READ_FILE_INTO_MEMORY,
361 PLDM_ERROR_INVALID_LENGTH, 0, responsePtr);
362 return response;
363 }
364
365 int responseCode = decode_rw_file_memory_req(
366 request, payloadLength, &fileHandle, &offset, &length, &address);
367 if (responseCode != PLDM_SUCCESS)
368 {
369 error(
370 "Failed to decode read file into memory request, response code '{RC}'",
371 "RC", responseCode);
372 }
373
374 using namespace pldm::filetable;
375 auto& table = buildFileTable(FILE_TABLE_JSON);
376 FileEntry value{};
377
378 try
379 {
380 value = table.at(fileHandle);
381 }
382 catch (const std::exception& e)
383 {
384 error(
385 "File handle '{HANDLE}' does not exist in the file table, error - {ERROR}",
386 "HANDLE", fileHandle, "ERROR", e);
387 encodeRWResponseHandler(request->hdr.instance_id,
388 PLDM_READ_FILE_INTO_MEMORY,
389 PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
390 return response;
391 }
392
393 if (!fs::exists(value.fsPath))
394 {
395 error("File '{PATH}' and handle '{FILE_HANDLE}' with does not exist",
396 "PATH", value.fsPath, "FILE_HANDLE", fileHandle);
397 encodeRWResponseHandler(request->hdr.instance_id,
398 PLDM_READ_FILE_INTO_MEMORY,
399 PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
400 return response;
401 }
402
403 auto fileSize = fs::file_size(value.fsPath);
404 if (!fileSize)
405 {
406 error(
407 "Failed to PLDM_READ_FILE_INTO_MEMORY from file {PATH} with size '{SIZE}'",
408 "PATH", value.fsPath, "SIZE", fileSize);
409 encodeRWResponseHandler(request->hdr.instance_id,
410 PLDM_READ_FILE_INTO_MEMORY,
411 PLDM_DATA_OUT_OF_RANGE, 0, responsePtr);
412 return response;
413 }
414 if (offset >= fileSize)
415 {
416 error(
417 "Offset '{OFFSET}' exceeds file size '{SIZE}' and file handle '{FILE_HANDLE}'",
418 "OFFSET", offset, "SIZE", fileSize, "FILE_HANDLE", fileHandle);
419 encodeRWResponseHandler(request->hdr.instance_id,
420 PLDM_READ_FILE_INTO_MEMORY,
421 PLDM_DATA_OUT_OF_RANGE, 0, responsePtr);
422 return response;
423 }
424
425 if (offset + length > fileSize)
426 {
427 length = fileSize - offset;
428 }
429
430 if (!length || length % dma::minSize)
431 {
432 error("Packet length '{LENGTH}' is non multiple of minimum DMA size",
433 "LENGTH", length);
434 encodeRWResponseHandler(request->hdr.instance_id,
435 PLDM_READ_FILE_INTO_MEMORY,
436 PLDM_ERROR_INVALID_LENGTH, 0, responsePtr);
437 return response;
438 }
439
440 using namespace dma;
441 DMA intf;
442 return transferAll<DMA>(&intf, PLDM_READ_FILE_INTO_MEMORY, value.fsPath,
443 offset, length, address, true,
444 request->hdr.instance_id);
445 }
446
writeFileFromMemory(const pldm_msg * request,size_t payloadLength)447 Response Handler::writeFileFromMemory(const pldm_msg* request,
448 size_t payloadLength)
449 {
450 uint32_t fileHandle = 0;
451 uint32_t offset = 0;
452 uint32_t length = 0;
453 uint64_t address = 0;
454
455 Response response(sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_RESP_BYTES, 0);
456 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
457
458 if (payloadLength != PLDM_RW_FILE_MEM_REQ_BYTES)
459 {
460 error(
461 "Failed to write file from memory as payload length '{LENGTH}' not equal to '{REQ_LENGTH}'",
462 "LENGTH", payloadLength, "REQ_LENGTH", PLDM_RW_FILE_MEM_REQ_BYTES);
463 encodeRWResponseHandler(request->hdr.instance_id,
464 PLDM_WRITE_FILE_FROM_MEMORY,
465 PLDM_ERROR_INVALID_LENGTH, 0, responsePtr);
466 return response;
467 }
468
469 int responseCode = decode_rw_file_memory_req(
470 request, payloadLength, &fileHandle, &offset, &length, &address);
471 if (responseCode != PLDM_SUCCESS)
472 {
473 error(
474 "Failed to decode write file from memory request, response code '{RC}'",
475 "RC", responseCode);
476 }
477
478 if (!length || length % dma::minSize)
479 {
480 error("Packet length '{LENGTH}' is non multiple of minimum DMA size",
481 "LENGTH", length);
482 encodeRWResponseHandler(request->hdr.instance_id,
483 PLDM_WRITE_FILE_FROM_MEMORY,
484 PLDM_ERROR_INVALID_LENGTH, 0, responsePtr);
485 return response;
486 }
487
488 using namespace pldm::filetable;
489 auto& table = buildFileTable(FILE_TABLE_JSON);
490 FileEntry value{};
491
492 try
493 {
494 value = table.at(fileHandle);
495 }
496 catch (const std::exception& e)
497 {
498 error(
499 "File handle '{HANDLE}' does not exist in the file table, error - {ERROR}",
500 "HANDLE", fileHandle, "ERROR", e);
501 encodeRWResponseHandler(request->hdr.instance_id,
502 PLDM_WRITE_FILE_FROM_MEMORY,
503 PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
504 return response;
505 }
506
507 if (!fs::exists(value.fsPath))
508 {
509 error("File '{PATH}' does not exist for file handle '{FILE_HANDLE}'",
510 "PATH", value.fsPath, "FILE_HANDLE", fileHandle);
511 encodeRWResponseHandler(request->hdr.instance_id,
512 PLDM_WRITE_FILE_FROM_MEMORY,
513 PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
514 return response;
515 }
516
517 auto fileSize = fs::file_size(value.fsPath);
518 if (!fileSize)
519 {
520 info(
521 "File '{PATH}' has size '{SIZE}' for command PLDM_WRITE_FILE_FROM_MEMORY",
522 "PATH", value.fsPath, "SIZE", fileSize);
523 }
524 if (offset >= fileSize)
525 {
526 error(
527 "Offset '{OFFSET}' exceeds file size {SIZE} for file '{PATH} and handle {FILE_HANDLE}",
528 "OFFSET", offset, "SIZE", fileSize, "PATH", value.fsPath,
529 "FILE_HANDLE", fileHandle);
530 encodeRWResponseHandler(request->hdr.instance_id,
531 PLDM_WRITE_FILE_FROM_MEMORY,
532 PLDM_DATA_OUT_OF_RANGE, 0, responsePtr);
533 return response;
534 }
535
536 using namespace dma;
537 DMA intf;
538 return transferAll<DMA>(&intf, PLDM_WRITE_FILE_FROM_MEMORY, value.fsPath,
539 offset, length, address, false,
540 request->hdr.instance_id);
541 }
542
getFileTable(const pldm_msg * request,size_t payloadLength)543 Response Handler::getFileTable(const pldm_msg* request, size_t payloadLength)
544 {
545 uint32_t transferHandle = 0;
546 uint8_t transferFlag = 0;
547 uint8_t tableType = 0;
548
549 Response response(
550 sizeof(pldm_msg_hdr) + PLDM_GET_FILE_TABLE_MIN_RESP_BYTES);
551 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
552
553 if (payloadLength != PLDM_GET_FILE_TABLE_REQ_BYTES)
554 {
555 error(
556 "Failed to get file table as payload length '{LENGTH}' not equal to required length '{REQ_LENGTH}'",
557 "LENGTH", payloadLength, "REQ_LENGTH",
558 PLDM_GET_FILE_TABLE_REQ_BYTES);
559 encodeGetFileResponseHandler(request->hdr.instance_id,
560 PLDM_ERROR_INVALID_LENGTH, 0, 0, nullptr,
561 0, responsePtr);
562 return response;
563 }
564
565 auto rc = decode_get_file_table_req(request, payloadLength, &transferHandle,
566 &transferFlag, &tableType);
567 if (rc)
568 {
569 error("Failed to decode get file table request, response code '{RC}'",
570 "RC", rc);
571 encodeGetFileResponseHandler(request->hdr.instance_id, rc, 0, 0,
572 nullptr, 0, responsePtr);
573 return response;
574 }
575
576 if (tableType != PLDM_FILE_ATTRIBUTE_TABLE)
577 {
578 error(
579 "Failed to match table type '{TYPE}' with expected table type '{REQ_TYPE}'",
580 "TYPE", tableType, "REQ_TYPE", PLDM_FILE_ATTRIBUTE_TABLE);
581 encodeGetFileResponseHandler(request->hdr.instance_id,
582 PLDM_INVALID_FILE_TABLE_TYPE, 0, 0,
583 nullptr, 0, responsePtr);
584 return response;
585 }
586
587 using namespace pldm::filetable;
588 auto table = buildFileTable(FILE_TABLE_JSON);
589 auto attrTable = table();
590 response.resize(response.size() + attrTable.size());
591 responsePtr = reinterpret_cast<pldm_msg*>(response.data());
592
593 if (attrTable.empty())
594 {
595 error("PLDM file attribute table is empty");
596 encodeGetFileResponseHandler(request->hdr.instance_id,
597 PLDM_FILE_TABLE_UNAVAILABLE, 0, 0, nullptr,
598 0, responsePtr);
599 return response;
600 }
601
602 encodeGetFileResponseHandler(request->hdr.instance_id, PLDM_SUCCESS, 0,
603 PLDM_START_AND_END, attrTable.data(),
604 attrTable.size(), responsePtr);
605 return response;
606 }
607
readFile(const pldm_msg * request,size_t payloadLength)608 Response Handler::readFile(const pldm_msg* request, size_t payloadLength)
609 {
610 uint32_t fileHandle = 0;
611 uint32_t offset = 0;
612 uint32_t length = 0;
613
614 Response response(sizeof(pldm_msg_hdr) + PLDM_READ_FILE_RESP_BYTES);
615 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
616
617 if (payloadLength != PLDM_READ_FILE_REQ_BYTES)
618 {
619 error(
620 "Failed to read file as payload length '{LENGTH}' not equal to '{REQ_LENGTH}'",
621 "LENGTH", payloadLength, "REQ_LENGTH", PLDM_READ_FILE_REQ_BYTES);
622 encodeReadResponseHandler(request->hdr.instance_id,
623 PLDM_ERROR_INVALID_LENGTH, length,
624 responsePtr);
625 return response;
626 }
627
628 auto rc = decode_read_file_req(request, payloadLength, &fileHandle, &offset,
629 &length);
630
631 if (rc)
632 {
633 error("Failed to decode read file request, response code '{RC}'", "RC",
634 rc);
635 encodeReadResponseHandler(request->hdr.instance_id, rc, 0, responsePtr);
636 return response;
637 }
638
639 using namespace pldm::filetable;
640 auto& table = buildFileTable(FILE_TABLE_JSON);
641 FileEntry value{};
642
643 try
644 {
645 value = table.at(fileHandle);
646 }
647 catch (const std::exception& e)
648 {
649 error(
650 "File handle '{HANDLE}' does not exist in the file table, error - {ERROR}",
651 "HANDLE", fileHandle, "ERROR", e);
652
653 encodeReadResponseHandler(request->hdr.instance_id,
654 PLDM_INVALID_FILE_HANDLE, length,
655 responsePtr);
656 return response;
657 }
658
659 if (!fs::exists(value.fsPath))
660 {
661 error("File '{PATH}' and handle {FILE_HANDLE} does not exist", "PATH",
662 value.fsPath, "FILE_HANDLE", fileHandle);
663 encodeReadResponseHandler(request->hdr.instance_id,
664 PLDM_INVALID_FILE_HANDLE, length,
665 responsePtr);
666 return response;
667 }
668
669 auto fileSize = fs::file_size(value.fsPath);
670 if (!fileSize)
671 {
672 error("Failed to read file {PATH} with size '{SIZE}'", "PATH",
673 value.fsPath, "SIZE", fileSize);
674 encodeRWResponseHandler(request->hdr.instance_id,
675 PLDM_READ_FILE_INTO_MEMORY,
676 PLDM_DATA_OUT_OF_RANGE, 0, responsePtr);
677 return response;
678 }
679
680 if (offset >= fileSize)
681 {
682 error(
683 "Offset '{OFFSET}' exceeds file size '{SIZE}' for file '{PATH}' and file handle '{HANDLE}'",
684 "OFFSET", offset, "SIZE", fileSize, "PATH", value.fsPath, "HANDLE",
685 fileHandle);
686 encodeReadResponseHandler(request->hdr.instance_id,
687 PLDM_DATA_OUT_OF_RANGE, length, responsePtr);
688 return response;
689 }
690
691 if (offset + length > fileSize)
692 {
693 length = fileSize - offset;
694 }
695
696 response.resize(response.size() + length);
697 responsePtr = reinterpret_cast<pldm_msg*>(response.data());
698 auto fileDataPos = reinterpret_cast<char*>(responsePtr);
699 fileDataPos += sizeof(pldm_msg_hdr) + sizeof(uint8_t) + sizeof(length);
700
701 std::ifstream stream(value.fsPath, std::ios::in | std::ios::binary);
702 stream.seekg(offset);
703 stream.read(fileDataPos, length);
704
705 encodeReadResponseHandler(request->hdr.instance_id, PLDM_SUCCESS, length,
706 responsePtr);
707
708 return response;
709 }
710
writeFile(const pldm_msg * request,size_t payloadLength)711 Response Handler::writeFile(const pldm_msg* request, size_t payloadLength)
712 {
713 uint32_t fileHandle = 0;
714 uint32_t offset = 0;
715 uint32_t length = 0;
716 size_t fileDataOffset = 0;
717
718 Response response(sizeof(pldm_msg_hdr) + PLDM_WRITE_FILE_RESP_BYTES);
719 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
720
721 if (payloadLength < PLDM_WRITE_FILE_REQ_BYTES)
722 {
723 error(
724 "Failed to write file as payload length '{LENGTH}' less than '{REQ_LENGTH}'",
725 "LENGTH", payloadLength, "REQ_LENGTH", PLDM_WRITE_FILE_REQ_BYTES);
726 encodeWriteResponseHandler(request->hdr.instance_id,
727 PLDM_ERROR_INVALID_LENGTH, 0, responsePtr);
728 return response;
729 }
730
731 auto rc = decode_write_file_req(request, payloadLength, &fileHandle,
732 &offset, &length, &fileDataOffset);
733
734 if (rc)
735 {
736 error("Failed to decode write file request, response code '{RC}'", "RC",
737 rc);
738 encodeWriteResponseHandler(request->hdr.instance_id, rc, 0,
739 responsePtr);
740 return response;
741 }
742
743 using namespace pldm::filetable;
744 auto& table = buildFileTable(FILE_TABLE_JSON);
745 FileEntry value{};
746
747 try
748 {
749 value = table.at(fileHandle);
750 }
751 catch (const std::exception& e)
752 {
753 error(
754 "File handle '{HANDLE}' does not exist in the file table, error - {ERROR}",
755 "HANDLE", fileHandle, "ERROR", e);
756 encodeWriteResponseHandler(request->hdr.instance_id,
757 PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
758 return response;
759 }
760
761 if (!fs::exists(value.fsPath))
762 {
763 error("File '{PATH}' and handle {FILE_HANDLE} does not exist", "PATH",
764 value.fsPath, "FILE_HANDLE", fileHandle);
765 encodeWriteResponseHandler(request->hdr.instance_id,
766 PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
767 return response;
768 }
769
770 auto fileSize = fs::file_size(value.fsPath);
771
772 if (!fileSize)
773 {
774 info("File {PATH} has size '{SIZE}' for write file command", "PATH",
775 value.fsPath, "SIZE", fileSize);
776 }
777
778 if (offset >= fileSize)
779 {
780 error(
781 "Offset '{OFFSET}' exceeds file size '{SIZE}' for file '{PATH}' and handle {FILE_HANDLE}",
782 "OFFSET", offset, "SIZE", fileSize, "PATH", value.fsPath,
783 "FILE_HANDLE", fileHandle);
784 encodeWriteResponseHandler(request->hdr.instance_id,
785 PLDM_DATA_OUT_OF_RANGE, 0, responsePtr);
786 return response;
787 }
788
789 auto fileDataPos =
790 reinterpret_cast<const char*>(request->payload) + fileDataOffset;
791
792 std::ofstream stream(value.fsPath,
793 std::ios::in | std::ios::out | std::ios::binary);
794 stream.seekp(offset);
795 stream.write(fileDataPos, length);
796
797 encodeWriteResponseHandler(request->hdr.instance_id, PLDM_SUCCESS, length,
798 responsePtr);
799
800 return response;
801 }
802
rwFileByTypeIntoMemory(uint8_t cmd,const pldm_msg * request,size_t payloadLength,oem_platform::Handler * oemPlatformHandler)803 Response rwFileByTypeIntoMemory(uint8_t cmd, const pldm_msg* request,
804 size_t payloadLength,
805 oem_platform::Handler* oemPlatformHandler)
806 {
807 Response response(
808 sizeof(pldm_msg_hdr) + PLDM_RW_FILE_BY_TYPE_MEM_RESP_BYTES, 0);
809 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
810
811 if (payloadLength != PLDM_RW_FILE_BY_TYPE_MEM_REQ_BYTES)
812 {
813 error(
814 "Failed to read file into memory as payload length '{LENGTH}' not equal to '{REQ_LENGTH}'",
815 "LENGTH", payloadLength, "REQ_LENGTH",
816 PLDM_RW_FILE_BY_TYPE_MEM_REQ_BYTES);
817 encodeRWTypeMemoryResponseHandler(request->hdr.instance_id, cmd,
818 PLDM_ERROR_INVALID_LENGTH, 0,
819 responsePtr);
820 return response;
821 }
822
823 uint16_t fileType{};
824 uint32_t fileHandle{};
825 uint32_t offset{};
826 uint32_t length{};
827 uint64_t address{};
828 auto rc = decode_rw_file_by_type_memory_req(
829 request, payloadLength, &fileType, &fileHandle, &offset, &length,
830 &address);
831 if (rc != PLDM_SUCCESS)
832 {
833 error(
834 "Failed to decode read/write file by type memory request, response code '{RC}'",
835 "RC", rc);
836 encodeRWTypeMemoryResponseHandler(request->hdr.instance_id, cmd, rc, 0,
837 responsePtr);
838 return response;
839 }
840 if (!length || length % dma::minSize)
841 {
842 error(
843 "Packet length '{LENGTH}' is non multiple of minimum DMA size for command {CMD}",
844 "LENGTH", length, "CMD", cmd);
845 encodeRWTypeMemoryResponseHandler(request->hdr.instance_id, cmd,
846 PLDM_ERROR_INVALID_LENGTH, 0,
847 responsePtr);
848 return response;
849 }
850
851 std::unique_ptr<FileHandler> handler{};
852 try
853 {
854 handler = getHandlerByType(fileType, fileHandle);
855 }
856 catch (const InternalFailure& e)
857 {
858 error("Unknown file type '{TYPE}', error - {ERROR} ", "TYPE", fileType,
859 "ERROR", e);
860 encodeRWTypeMemoryResponseHandler(request->hdr.instance_id, cmd,
861 PLDM_INVALID_FILE_TYPE, 0,
862 responsePtr);
863 return response;
864 }
865
866 rc = cmd == PLDM_WRITE_FILE_BY_TYPE_FROM_MEMORY
867 ? handler->writeFromMemory(offset, length, address,
868 oemPlatformHandler)
869 : handler->readIntoMemory(offset, length, address,
870 oemPlatformHandler);
871 encodeRWTypeMemoryResponseHandler(request->hdr.instance_id, cmd, rc, length,
872 responsePtr);
873 return response;
874 }
875
writeFileByTypeFromMemory(const pldm_msg * request,size_t payloadLength)876 Response Handler::writeFileByTypeFromMemory(const pldm_msg* request,
877 size_t payloadLength)
878 {
879 return rwFileByTypeIntoMemory(PLDM_WRITE_FILE_BY_TYPE_FROM_MEMORY, request,
880 payloadLength, oemPlatformHandler);
881 }
882
readFileByTypeIntoMemory(const pldm_msg * request,size_t payloadLength)883 Response Handler::readFileByTypeIntoMemory(const pldm_msg* request,
884 size_t payloadLength)
885 {
886 return rwFileByTypeIntoMemory(PLDM_READ_FILE_BY_TYPE_INTO_MEMORY, request,
887 payloadLength, oemPlatformHandler);
888 }
889
writeFileByType(const pldm_msg * request,size_t payloadLength)890 Response Handler::writeFileByType(const pldm_msg* request, size_t payloadLength)
891 {
892 Response response(sizeof(pldm_msg_hdr) + PLDM_RW_FILE_BY_TYPE_RESP_BYTES);
893 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
894
895 if (payloadLength < PLDM_RW_FILE_BY_TYPE_REQ_BYTES)
896 {
897 error(
898 "Failed to write file by type as payload length '{LENGTH}' less than '{REQ_LENGTH}'",
899 "LENGTH", payloadLength, "REQ_LENGTH",
900 PLDM_RW_FILE_BY_TYPE_REQ_BYTES);
901 encodeRWTypeResponseHandler(request->hdr.instance_id,
902 PLDM_WRITE_FILE_BY_TYPE,
903 PLDM_ERROR_INVALID_LENGTH, 0, responsePtr);
904 return response;
905 }
906 uint16_t fileType{};
907 uint32_t fileHandle{};
908 uint32_t offset{};
909 uint32_t length{};
910
911 auto rc = decode_rw_file_by_type_req(request, payloadLength, &fileType,
912 &fileHandle, &offset, &length);
913 if (rc != PLDM_SUCCESS)
914 {
915 error("Failed decoded write file by type request, response code '{RC}'",
916 "RC", rc);
917 encodeRWTypeResponseHandler(request->hdr.instance_id,
918 PLDM_WRITE_FILE_BY_TYPE, rc, 0,
919 responsePtr);
920 return response;
921 }
922
923 std::unique_ptr<FileHandler> handler{};
924 try
925 {
926 handler = getHandlerByType(fileType, fileHandle);
927 }
928 catch (const InternalFailure& e)
929 {
930 error("Unknown file type '{TYPE}', error - {ERROR}", "TYPE", fileType,
931 "ERROR", e);
932 encodeRWTypeResponseHandler(request->hdr.instance_id,
933 PLDM_WRITE_FILE_BY_TYPE,
934 PLDM_INVALID_FILE_TYPE, 0, responsePtr);
935 return response;
936 }
937
938 rc = handler->write(reinterpret_cast<const char*>(
939 request->payload + PLDM_RW_FILE_BY_TYPE_REQ_BYTES),
940 offset, length, oemPlatformHandler);
941 encodeRWTypeResponseHandler(request->hdr.instance_id,
942 PLDM_WRITE_FILE_BY_TYPE, rc, length,
943 responsePtr);
944 return response;
945 }
946
readFileByType(const pldm_msg * request,size_t payloadLength)947 Response Handler::readFileByType(const pldm_msg* request, size_t payloadLength)
948 {
949 Response response(sizeof(pldm_msg_hdr) + PLDM_RW_FILE_BY_TYPE_RESP_BYTES);
950 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
951
952 if (payloadLength != PLDM_RW_FILE_BY_TYPE_REQ_BYTES)
953 {
954 error(
955 "Failed to read file by type as payload length '{LENGTH}' less than '{REQ_LENGTH}'",
956 "LENGTH", payloadLength, "REQ_LENGTH",
957 PLDM_RW_FILE_BY_TYPE_REQ_BYTES);
958 encodeRWTypeResponseHandler(request->hdr.instance_id,
959 PLDM_READ_FILE_BY_TYPE,
960 PLDM_ERROR_INVALID_LENGTH, 0, responsePtr);
961 return response;
962 }
963 uint16_t fileType{};
964 uint32_t fileHandle{};
965 uint32_t offset{};
966 uint32_t length{};
967
968 auto rc = decode_rw_file_by_type_req(request, payloadLength, &fileType,
969 &fileHandle, &offset, &length);
970 if (rc != PLDM_SUCCESS)
971 {
972 error(
973 "Failed to decode read file by type request, response code '{RC}'",
974 "RC", rc);
975 encodeRWTypeResponseHandler(request->hdr.instance_id,
976 PLDM_READ_FILE_BY_TYPE, rc, 0, responsePtr);
977 return response;
978 }
979
980 std::unique_ptr<FileHandler> handler{};
981 try
982 {
983 handler = getHandlerByType(fileType, fileHandle);
984 }
985 catch (const InternalFailure& e)
986 {
987 error("Unknown file type '{TYPE}', error - {ERROR}", "TYPE", fileType,
988 "ERROR", e);
989 encodeRWTypeResponseHandler(request->hdr.instance_id,
990 PLDM_READ_FILE_BY_TYPE,
991 PLDM_INVALID_FILE_TYPE, 0, responsePtr);
992 return response;
993 }
994
995 rc = handler->read(offset, length, response, oemPlatformHandler);
996 responsePtr = reinterpret_cast<pldm_msg*>(response.data());
997 encodeRWTypeResponseHandler(request->hdr.instance_id,
998 PLDM_READ_FILE_BY_TYPE, rc, length,
999 responsePtr);
1000 return response;
1001 }
1002
fileAck(const pldm_msg * request,size_t payloadLength)1003 Response Handler::fileAck(const pldm_msg* request, size_t payloadLength)
1004 {
1005 Response response(sizeof(pldm_msg_hdr) + PLDM_FILE_ACK_RESP_BYTES);
1006 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
1007
1008 if (payloadLength != PLDM_FILE_ACK_REQ_BYTES)
1009 {
1010 error(
1011 "Failed to do file ack as payload length '{LENGTH}' is less than '{REQ_LENGTH}'",
1012 "LENGTH", payloadLength, "REQ_LENGTH", PLDM_FILE_ACK_REQ_BYTES);
1013 encodeFileAckResponseHandler(request->hdr.instance_id,
1014 PLDM_ERROR_INVALID_LENGTH, responsePtr);
1015 return response;
1016 }
1017 uint16_t fileType{};
1018 uint32_t fileHandle{};
1019 uint8_t fileStatus{};
1020
1021 auto rc = decode_file_ack_req(request, payloadLength, &fileType,
1022 &fileHandle, &fileStatus);
1023 if (rc != PLDM_SUCCESS)
1024 {
1025 encodeFileAckResponseHandler(request->hdr.instance_id, rc, responsePtr);
1026 return response;
1027 }
1028
1029 std::unique_ptr<FileHandler> handler{};
1030 try
1031 {
1032 handler = getHandlerByType(fileType, fileHandle);
1033 }
1034
1035 catch (const InternalFailure& e)
1036 {
1037 error("Unknown file type '{TYPE}', error - {ERROR}", "TYPE", fileType,
1038 "ERROR", e);
1039 encodeFileAckResponseHandler(request->hdr.instance_id,
1040 PLDM_INVALID_FILE_TYPE, responsePtr);
1041 return response;
1042 }
1043
1044 rc = handler->fileAck(fileStatus);
1045 encodeFileAckResponseHandler(request->hdr.instance_id, rc, responsePtr);
1046 return response;
1047 }
1048
getAlertStatus(const pldm_msg * request,size_t payloadLength)1049 Response Handler::getAlertStatus(const pldm_msg* request, size_t payloadLength)
1050 {
1051 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_ALERT_STATUS_RESP_BYTES);
1052 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
1053 if (payloadLength != PLDM_GET_ALERT_STATUS_REQ_BYTES)
1054 {
1055 error(
1056 "Failed to get alert status as payload length '{LENGTH}' is less than '{REQ_LENGTH}'",
1057 "LENGTH", payloadLength, "REQ_LENGTH",
1058 PLDM_GET_ALERT_STATUS_REQ_BYTES);
1059 return CmdHandler::ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH);
1060 }
1061
1062 uint8_t versionId{};
1063
1064 auto rc = decode_get_alert_status_req(request, payloadLength, &versionId);
1065 if (rc != PLDM_SUCCESS)
1066 {
1067 error("Failed to decode get alert status request, response code '{RC}'",
1068 "RC", rc);
1069 return CmdHandler::ccOnlyResponse(request, rc);
1070 }
1071
1072 if (versionId != 0)
1073 {
1074 error(
1075 "Failed to get alert status due to unsupported version ID '{VERSION}'",
1076 "VERSION", versionId);
1077 return CmdHandler::ccOnlyResponse(request,
1078 PLDM_HOST_UNSUPPORTED_FORMAT_VERSION);
1079 }
1080
1081 constexpr uint32_t rackEntry = 0xFF000030;
1082 constexpr uint32_t priCecNode = 0x00008030;
1083 rc = encode_get_alert_status_resp(request->hdr.instance_id, PLDM_SUCCESS,
1084 rackEntry, priCecNode, responsePtr,
1085 PLDM_GET_ALERT_STATUS_RESP_BYTES);
1086 if (rc != PLDM_SUCCESS)
1087 {
1088 error(
1089 "Failed to encode get alert status response, response code '{RC}'",
1090 "RC", rc);
1091 return CmdHandler::ccOnlyResponse(request, rc);
1092 }
1093
1094 return response;
1095 }
1096
newFileAvailable(const pldm_msg * request,size_t payloadLength)1097 Response Handler::newFileAvailable(const pldm_msg* request,
1098 size_t payloadLength)
1099 {
1100 Response response(sizeof(pldm_msg_hdr) + PLDM_NEW_FILE_RESP_BYTES);
1101
1102 if (payloadLength != PLDM_NEW_FILE_REQ_BYTES)
1103 {
1104 error(
1105 "Failed new file available as payload length '{LENGTH}' is less than '{REQ_LENGTH}'",
1106 "LENGTH", payloadLength, "REQ_LENGTH", PLDM_NEW_FILE_REQ_BYTES);
1107 return CmdHandler::ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH);
1108 }
1109 uint16_t fileType{};
1110 uint32_t fileHandle{};
1111 uint64_t length{};
1112
1113 auto rc = decode_new_file_req(request, payloadLength, &fileType,
1114 &fileHandle, &length);
1115
1116 if (rc != PLDM_SUCCESS)
1117 {
1118 error("Failed to decode new file request, response code '{RC}'", "RC",
1119 rc);
1120 return CmdHandler::ccOnlyResponse(request, rc);
1121 }
1122
1123 std::unique_ptr<FileHandler> handler{};
1124 try
1125 {
1126 handler = getHandlerByType(fileType, fileHandle);
1127 }
1128 catch (const InternalFailure& e)
1129 {
1130 error("Unknown file type '{TYPE}', error - {ERROR}", "TYPE", fileType,
1131 "ERROR", e);
1132 return CmdHandler::ccOnlyResponse(request, PLDM_INVALID_FILE_TYPE);
1133 }
1134
1135 rc = handler->newFileAvailable(length);
1136 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
1137 int responseCode =
1138 encode_new_file_resp(request->hdr.instance_id, rc, responsePtr);
1139 if (responseCode != PLDM_SUCCESS)
1140 {
1141 error(
1142 "Failed to encode new file available response, response code '{RC}'",
1143 "RC", responseCode);
1144 }
1145 return response;
1146 }
1147
1148 } // namespace oem_ibm
1149 } // namespace responder
1150 } // namespace pldm
1151