1 #pragma once 2 3 #include <stdint.h> 4 #include <unistd.h> 5 6 #include <filesystem> 7 8 #include "libpldm/base.h" 9 #include "libpldm/file_io.h" 10 11 namespace pldm 12 { 13 14 namespace responder 15 { 16 17 using Response = std::vector<uint8_t>; 18 19 namespace utils 20 { 21 22 /** @struct CustomFD 23 * 24 * RAII wrapper for file descriptor. 25 */ 26 struct CustomFD 27 { 28 CustomFD(const CustomFD&) = delete; 29 CustomFD& operator=(const CustomFD&) = delete; 30 CustomFD(CustomFD&&) = delete; 31 CustomFD& operator=(CustomFD&&) = delete; 32 33 CustomFD(int fd) : fd(fd) 34 { 35 } 36 37 ~CustomFD() 38 { 39 if (fd >= 0) 40 { 41 close(fd); 42 } 43 } 44 45 int operator()() const 46 { 47 return fd; 48 } 49 50 private: 51 int fd = -1; 52 }; 53 54 } // namespace utils 55 56 namespace dma 57 { 58 59 // The minimum data size of dma transfer in bytes 60 constexpr uint32_t minSize = 16; 61 62 // 16MB - 4096B (16773120 bytes) is the maximum data size of DMA transfer 63 constexpr size_t maxSize = (16 * 1024 * 1024) - 4096; 64 65 namespace fs = std::filesystem; 66 67 /** 68 * @class DMA 69 * 70 * Expose API to initiate transfer of data by DMA 71 * 72 * This class only exposes the public API transferDataHost to transfer data 73 * between BMC and host using DMA. This allows for mocking the transferDataHost 74 * for unit testing purposes. 75 */ 76 class DMA 77 { 78 public: 79 /** @brief API to transfer data between BMC and host using DMA 80 * 81 * @param[in] path - pathname of the file to transfer data from or to 82 * @param[in] offset - offset in the file 83 * @param[in] length - length of the data to transfer 84 * @param[in] address - DMA address on the host 85 * @param[in] upstream - indicates direction of the transfer; true indicates 86 * transfer to the host 87 * 88 * @return returns 0 on success, negative errno on failure 89 */ 90 int transferDataHost(const fs::path& path, uint32_t offset, uint32_t length, 91 uint64_t address, bool upstream); 92 }; 93 94 /** @brief Transfer the data between BMC and host using DMA. 95 * 96 * There is a max size for each DMA operation, transferAll API abstracts this 97 * and the requested length is broken down into multiple DMA operations if the 98 * length exceed max size. 99 * 100 * @tparam[in] T - DMA interface type 101 * @param[in] intf - interface passed to invoke DMA transfer 102 * @param[in] command - PLDM command 103 * @param[in] path - pathname of the file to transfer data from or to 104 * @param[in] offset - offset in the file 105 * @param[in] length - length of the data to transfer 106 * @param[in] address - DMA address on the host 107 * @param[in] upstream - indicates direction of the transfer; true indicates 108 * transfer to the host 109 * @return PLDM response message 110 */ 111 112 template <class DMAInterface> 113 Response transferAll(DMAInterface* intf, uint8_t command, fs::path& path, 114 uint32_t offset, uint32_t length, uint64_t address, 115 bool upstream) 116 { 117 uint32_t origLength = length; 118 Response response(sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_RESP_BYTES, 0); 119 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 120 121 while (length > dma::maxSize) 122 { 123 auto rc = intf->transferDataHost(path, offset, dma::maxSize, address, 124 upstream); 125 if (rc < 0) 126 { 127 encode_rw_file_memory_resp(0, command, PLDM_ERROR, 0, responsePtr); 128 return response; 129 } 130 131 offset += dma::maxSize; 132 length -= dma::maxSize; 133 address += dma::maxSize; 134 } 135 136 auto rc = intf->transferDataHost(path, offset, length, address, upstream); 137 if (rc < 0) 138 { 139 encode_rw_file_memory_resp(0, command, PLDM_ERROR, 0, responsePtr); 140 return response; 141 } 142 143 encode_rw_file_memory_resp(0, command, PLDM_SUCCESS, origLength, 144 responsePtr); 145 return response; 146 } 147 148 } // namespace dma 149 150 /** @brief Handler for readFileIntoMemory command 151 * 152 * @param[in] request - pointer to PLDM request payload 153 * @param[in] payloadLength - length of the message payload 154 * 155 * @return PLDM response message 156 */ 157 Response readFileIntoMemory(const uint8_t* request, size_t payloadLength); 158 159 /** @brief Handler for writeFileIntoMemory command 160 * 161 * @param[in] request - pointer to PLDM request payload 162 * @param[in] payloadLength - length of the message payload 163 * 164 * @return PLDM response message 165 */ 166 Response writeFileFromMemory(const uint8_t* request, size_t payloadLength); 167 } // namespace responder 168 } // namespace pldm 169