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 <unistd.h>
16
17 #include <phosphor-logging/lg2.hpp>
18 #include <xyz/openbmc_project/Logging/Entry/server.hpp>
19
20 #include <cstdint>
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
transferFileData(int32_t fd,bool upstream,uint32_t offset,uint32_t & length,uint64_t address)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 =
51 xdmaInterface.transferDataHost(fd, offset, length, address, upstream);
52 return rc < 0 ? PLDM_ERROR : PLDM_SUCCESS;
53 }
54
transferFileDataToSocket(int32_t fd,uint32_t & length,uint64_t address)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 =
62 xdmaInterface.transferHostDataToSocket(fd, dma::maxSize, 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
transferFileData(const fs::path & path,bool upstream,uint32_t offset,uint32_t & length,uint64_t address)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
getHandlerByType(uint16_t fileType,uint32_t fileHandle)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
readFile(const std::string & filePath,uint32_t offset,uint32_t & length,Response & response)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