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 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 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 { 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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