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 = 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 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( 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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