1 #include "file_io_by_type.hpp" 2 3 #include "common/utils.hpp" 4 #include "file_io_type_cert.hpp" 5 #include "file_io_type_dump.hpp" 6 #include "file_io_type_lid.hpp" 7 #include "file_io_type_pcie.hpp" 8 #include "file_io_type_pel.hpp" 9 #include "file_io_type_progress_src.hpp" 10 #include "file_io_type_vpd.hpp" 11 #include "xyz/openbmc_project/Common/error.hpp" 12 13 #include <libpldm/base.h> 14 #include <libpldm/oem/ibm/file_io.h> 15 #include <stdint.h> 16 #include <unistd.h> 17 18 #include <phosphor-logging/lg2.hpp> 19 #include <xyz/openbmc_project/Logging/Entry/server.hpp> 20 21 #include <exception> 22 #include <filesystem> 23 #include <fstream> 24 #include <vector> 25 26 PHOSPHOR_LOG2_USING; 27 28 namespace pldm 29 { 30 namespace responder 31 { 32 using namespace sdbusplus::xyz::openbmc_project::Common::Error; 33 34 int FileHandler::transferFileData(int32_t fd, bool upstream, uint32_t offset, 35 uint32_t& length, uint64_t address) 36 { 37 dma::DMA xdmaInterface; 38 while (length > dma::maxSize) 39 { 40 auto rc = xdmaInterface.transferDataHost(fd, offset, dma::maxSize, 41 address, upstream); 42 if (rc < 0) 43 { 44 return PLDM_ERROR; 45 } 46 offset += dma::maxSize; 47 length -= dma::maxSize; 48 address += dma::maxSize; 49 } 50 auto rc = xdmaInterface.transferDataHost(fd, offset, length, address, 51 upstream); 52 return rc < 0 ? PLDM_ERROR : PLDM_SUCCESS; 53 } 54 55 int FileHandler::transferFileDataToSocket(int32_t fd, uint32_t& length, 56 uint64_t address) 57 { 58 dma::DMA xdmaInterface; 59 while (length > dma::maxSize) 60 { 61 auto rc = xdmaInterface.transferHostDataToSocket(fd, dma::maxSize, 62 address); 63 if (rc < 0) 64 { 65 return PLDM_ERROR; 66 } 67 length -= dma::maxSize; 68 address += dma::maxSize; 69 } 70 auto rc = xdmaInterface.transferHostDataToSocket(fd, length, address); 71 return rc < 0 ? PLDM_ERROR : PLDM_SUCCESS; 72 } 73 74 int FileHandler::transferFileData(const fs::path& path, bool upstream, 75 uint32_t offset, uint32_t& length, 76 uint64_t address) 77 { 78 bool fileExists = false; 79 if (upstream) 80 { 81 fileExists = fs::exists(path); 82 if (!fileExists) 83 { 84 error("File '{PATH}' does not exist.", "PATH", path); 85 return PLDM_INVALID_FILE_HANDLE; 86 } 87 88 size_t fileSize = fs::file_size(path); 89 if (offset >= fileSize) 90 { 91 error( 92 "Offset '{OFFSET}' exceeds file size '{SIZE}' for file handle {FILE_HANDLE}", 93 "OFFSET", offset, "SIZE", fileSize, "FILE_HANDLE", fileHandle); 94 return PLDM_DATA_OUT_OF_RANGE; 95 } 96 if (offset + length > fileSize) 97 { 98 length = fileSize - offset; 99 } 100 } 101 102 int flags{}; 103 if (upstream) 104 { 105 flags = O_RDONLY; 106 } 107 else if (fileExists) 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 error("File '{PATH}' does not exist.", "PATH", path); 119 return PLDM_ERROR; 120 } 121 utils::CustomFD fd(file); 122 123 return transferFileData(fd(), upstream, offset, length, address); 124 } 125 126 std::unique_ptr<FileHandler> getHandlerByType(uint16_t fileType, 127 uint32_t fileHandle) 128 { 129 switch (fileType) 130 { 131 case PLDM_FILE_TYPE_PEL: 132 { 133 return std::make_unique<PelHandler>(fileHandle); 134 } 135 case PLDM_FILE_TYPE_LID_PERM: 136 { 137 return std::make_unique<LidHandler>(fileHandle, true); 138 } 139 case PLDM_FILE_TYPE_LID_TEMP: 140 { 141 return std::make_unique<LidHandler>(fileHandle, false); 142 } 143 case PLDM_FILE_TYPE_LID_MARKER: 144 { 145 return std::make_unique<LidHandler>(fileHandle, false, 146 PLDM_FILE_TYPE_LID_MARKER); 147 } 148 case PLDM_FILE_TYPE_DUMP: 149 case PLDM_FILE_TYPE_RESOURCE_DUMP_PARMS: 150 case PLDM_FILE_TYPE_RESOURCE_DUMP: 151 { 152 return std::make_unique<DumpHandler>(fileHandle, fileType); 153 } 154 case PLDM_FILE_TYPE_CERT_SIGNING_REQUEST: 155 case PLDM_FILE_TYPE_SIGNED_CERT: 156 case PLDM_FILE_TYPE_ROOT_CERT: 157 { 158 return std::make_unique<CertHandler>(fileHandle, fileType); 159 } 160 case PLDM_FILE_TYPE_PROGRESS_SRC: 161 { 162 return std::make_unique<ProgressCodeHandler>(fileHandle); 163 } 164 case PLDM_FILE_TYPE_LID_RUNNING: 165 { 166 return std::make_unique<LidHandler>(fileHandle, false, 167 PLDM_FILE_TYPE_LID_RUNNING); 168 } 169 case PLDM_FILE_TYPE_PSPD_VPD_PDD_KEYWORD: 170 { 171 return std::make_unique<keywordHandler>(fileHandle, fileType); 172 } 173 case PLDM_FILE_TYPE_PCIE_TOPOLOGY: 174 case PLDM_FILE_TYPE_CABLE_INFO: 175 { 176 return std::make_unique<PCIeInfoHandler>(fileHandle, fileType); 177 } 178 default: 179 { 180 throw InternalFailure(); 181 break; 182 } 183 } 184 return nullptr; 185 } 186 187 int FileHandler::readFile(const std::string& filePath, uint32_t offset, 188 uint32_t& length, Response& response) 189 { 190 if (!fs::exists(filePath)) 191 { 192 error("File '{PATH}' and handle {FILE_HANDLE} does not exist", "PATH", 193 filePath, "FILE_HANDLE", fileHandle); 194 return PLDM_INVALID_FILE_HANDLE; 195 } 196 197 size_t fileSize = fs::file_size(filePath); 198 if (offset >= fileSize) 199 { 200 error( 201 "Offset '{OFFSET}' exceeds file size '{SIZE}' and file handle '{FILE_HANDLE}'", 202 "OFFSET", offset, "SIZE", fileSize, "FILE_HANDLE", fileHandle); 203 return PLDM_DATA_OUT_OF_RANGE; 204 } 205 206 if (offset + length > fileSize) 207 { 208 length = fileSize - offset; 209 } 210 211 size_t currSize = response.size(); 212 response.resize(currSize + length); 213 auto filePos = reinterpret_cast<char*>(response.data()); 214 filePos += currSize; 215 std::ifstream stream(filePath, std::ios::in | std::ios::binary); 216 if (stream) 217 { 218 stream.seekg(offset); 219 stream.read(filePos, length); 220 return PLDM_SUCCESS; 221 } 222 error( 223 "Unable to read file '{PATH}' at offset '{OFFSET}' for length '{LENGTH}'", 224 "PATH", filePath, "OFFSET", offset, "LENGTH", length); 225 return PLDM_ERROR; 226 } 227 228 } // namespace responder 229 } // namespace pldm 230