1 #pragma once 2 3 #include "handler.hpp" 4 #include "utils.hpp" 5 6 #include <fcntl.h> 7 #include <stdint.h> 8 #include <sys/stat.h> 9 #include <sys/types.h> 10 #include <unistd.h> 11 12 #include <filesystem> 13 #include <iostream> 14 #include <vector> 15 16 #include "libpldm/base.h" 17 #include "oem/ibm/libpldm/file_io.h" 18 19 namespace pldm 20 { 21 namespace responder 22 { 23 namespace dma 24 { 25 26 // The minimum data size of dma transfer in bytes 27 constexpr uint32_t minSize = 16; 28 29 // 16MB - 4096B (16773120 bytes) is the maximum data size of DMA transfer 30 constexpr size_t maxSize = (16 * 1024 * 1024) - 4096; 31 32 namespace fs = std::filesystem; 33 34 /** 35 * @class DMA 36 * 37 * Expose API to initiate transfer of data by DMA 38 * 39 * This class only exposes the public API transferDataHost to transfer data 40 * between BMC and host using DMA. This allows for mocking the transferDataHost 41 * for unit testing purposes. 42 */ 43 class DMA 44 { 45 public: 46 /** @brief API to transfer data between BMC and host using DMA 47 * 48 * @param[in] path - pathname of the file to transfer data from or to 49 * @param[in] offset - offset in the file 50 * @param[in] length - length of the data to transfer 51 * @param[in] address - DMA address on the host 52 * @param[in] upstream - indicates direction of the transfer; true indicates 53 * transfer to the host 54 * 55 * @return returns 0 on success, negative errno on failure 56 */ 57 int transferDataHost(int fd, uint32_t offset, uint32_t length, 58 uint64_t address, bool upstream); 59 }; 60 61 /** @brief Transfer the data between BMC and host using DMA. 62 * 63 * There is a max size for each DMA operation, transferAll API abstracts this 64 * and the requested length is broken down into multiple DMA operations if the 65 * length exceed max size. 66 * 67 * @tparam[in] T - DMA interface type 68 * @param[in] intf - interface passed to invoke DMA transfer 69 * @param[in] command - PLDM command 70 * @param[in] path - pathname of the file to transfer data from or to 71 * @param[in] offset - offset in the file 72 * @param[in] length - length of the data to transfer 73 * @param[in] address - DMA address on the host 74 * @param[in] upstream - indicates direction of the transfer; true indicates 75 * transfer to the host 76 * @param[in] instanceId - Message's instance id 77 * @return PLDM response message 78 */ 79 80 template <class DMAInterface> 81 Response transferAll(DMAInterface* intf, uint8_t command, fs::path& path, 82 uint32_t offset, uint32_t length, uint64_t address, 83 bool upstream, uint8_t instanceId) 84 { 85 uint32_t origLength = length; 86 Response response(sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_RESP_BYTES, 0); 87 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 88 89 int flags{}; 90 if (upstream) 91 { 92 flags = O_RDONLY; 93 } 94 else if (fs::exists(path)) 95 { 96 flags = O_RDWR; 97 } 98 else 99 { 100 flags = O_WRONLY; 101 } 102 int file = open(path.string().c_str(), flags); 103 if (file == -1) 104 { 105 std::cerr << "File does not exist, path = " << path.string() << "\n"; 106 encode_rw_file_memory_resp(instanceId, command, PLDM_ERROR, 0, 107 responsePtr); 108 return response; 109 } 110 pldm::utils::CustomFD fd(file); 111 112 while (length > dma::maxSize) 113 { 114 auto rc = intf->transferDataHost(fd(), offset, dma::maxSize, address, 115 upstream); 116 if (rc < 0) 117 { 118 encode_rw_file_memory_resp(instanceId, command, PLDM_ERROR, 0, 119 responsePtr); 120 return response; 121 } 122 123 offset += dma::maxSize; 124 length -= dma::maxSize; 125 address += dma::maxSize; 126 } 127 128 auto rc = intf->transferDataHost(fd(), offset, length, address, upstream); 129 if (rc < 0) 130 { 131 encode_rw_file_memory_resp(instanceId, command, PLDM_ERROR, 0, 132 responsePtr); 133 return response; 134 } 135 136 encode_rw_file_memory_resp(instanceId, command, PLDM_SUCCESS, origLength, 137 responsePtr); 138 return response; 139 } 140 141 } // namespace dma 142 143 namespace oem_ibm 144 { 145 146 class Handler : public CmdHandler 147 { 148 public: 149 Handler() 150 { 151 handlers.emplace(PLDM_READ_FILE_INTO_MEMORY, 152 [this](const pldm_msg* request, size_t payloadLength) { 153 return this->readFileIntoMemory(request, 154 payloadLength); 155 }); 156 handlers.emplace(PLDM_WRITE_FILE_FROM_MEMORY, 157 [this](const pldm_msg* request, size_t payloadLength) { 158 return this->writeFileFromMemory(request, 159 payloadLength); 160 }); 161 handlers.emplace(PLDM_WRITE_FILE_BY_TYPE_FROM_MEMORY, 162 [this](const pldm_msg* request, size_t payloadLength) { 163 return this->writeFileByTypeFromMemory( 164 request, payloadLength); 165 }); 166 handlers.emplace(PLDM_READ_FILE_BY_TYPE_INTO_MEMORY, 167 [this](const pldm_msg* request, size_t payloadLength) { 168 return this->readFileByTypeIntoMemory( 169 request, payloadLength); 170 }); 171 handlers.emplace(PLDM_READ_FILE_BY_TYPE, [this](const pldm_msg* request, 172 size_t payloadLength) { 173 return this->readFileByType(request, payloadLength); 174 }); 175 handlers.emplace(PLDM_GET_FILE_TABLE, 176 [this](const pldm_msg* request, size_t payloadLength) { 177 return this->getFileTable(request, payloadLength); 178 }); 179 handlers.emplace(PLDM_READ_FILE, 180 [this](const pldm_msg* request, size_t payloadLength) { 181 return this->readFile(request, payloadLength); 182 }); 183 handlers.emplace(PLDM_WRITE_FILE, 184 [this](const pldm_msg* request, size_t payloadLength) { 185 return this->writeFile(request, payloadLength); 186 }); 187 handlers.emplace(PLDM_FILE_ACK, 188 [this](const pldm_msg* request, size_t payloadLength) { 189 return this->fileAck(request, payloadLength); 190 }); 191 } 192 193 /** @brief Handler for readFileIntoMemory command 194 * 195 * @param[in] request - pointer to PLDM request payload 196 * @param[in] payloadLength - length of the message 197 * 198 * @return PLDM response message 199 */ 200 Response readFileIntoMemory(const pldm_msg* request, size_t payloadLength); 201 202 /** @brief Handler for writeFileIntoMemory command 203 * 204 * @param[in] request - pointer to PLDM request payload 205 * @param[in] payloadLength - length of the message 206 * 207 * @return PLDM response message 208 */ 209 Response writeFileFromMemory(const pldm_msg* request, size_t payloadLength); 210 211 /** @brief Handler for writeFileByTypeFromMemory command 212 * 213 * @param[in] request - pointer to PLDM request payload 214 * @param[in] payloadLength - length of the message 215 * 216 * @return PLDM response message 217 */ 218 219 Response writeFileByTypeFromMemory(const pldm_msg* request, 220 size_t payloadLength); 221 222 /** @brief Handler for readFileByTypeIntoMemory command 223 * 224 * @param[in] request - pointer to PLDM request payload 225 * @param[in] payloadLength - length of the message 226 * 227 * @return PLDM response message 228 */ 229 Response readFileByTypeIntoMemory(const pldm_msg* request, 230 size_t payloadLength); 231 232 /** @brief Handler for readFileByType command 233 * 234 * @param[in] request - pointer to PLDM request payload 235 * @param[in] payloadLength - length of the message 236 * 237 * @return PLDM response message 238 */ 239 Response readFileByType(const pldm_msg* request, size_t payloadLength); 240 241 /** @brief Handler for GetFileTable command 242 * 243 * @param[in] request - pointer to PLDM request payload 244 * @param[in] payloadLength - length of the message payload 245 * 246 * @return PLDM response message 247 */ 248 Response getFileTable(const pldm_msg* request, size_t payloadLength); 249 250 /** @brief Handler for readFile command 251 * 252 * @param[in] request - PLDM request msg 253 * @param[in] payloadLength - length of the message payload 254 * 255 * @return PLDM response message 256 */ 257 Response readFile(const pldm_msg* request, size_t payloadLength); 258 259 /** @brief Handler for writeFile command 260 * 261 * @param[in] request - PLDM request msg 262 * @param[in] payloadLength - length of the message payload 263 * 264 * @return PLDM response message 265 */ 266 Response writeFile(const pldm_msg* request, size_t payloadLength); 267 268 Response fileAck(const pldm_msg* request, size_t payloadLength); 269 }; 270 271 } // namespace oem_ibm 272 } // namespace responder 273 } // namespace pldm 274