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