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