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